1 /*
2  * cdrom.mp3.c  CD-ROM�Τ�����MP3file����
3  *
4  * Copyright (C) 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
5  *               1998-                           <masaki-c@is.aist-nara.ac.jp>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21 */
22 /* $Id: cdrom.mp3.c,v 1.24 2003/01/31 12:58:28 chikama Exp $ */
23 
24 #include "config.h"
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <glib.h>
35 
36 #ifdef HAVE_LIBGEN_H
37 #include <libgen.h>
38 #else  /* for FreeBSD 3.x ? */
39 #include "xpg_basename.c"
40 extern char *__xpg_basename __P ((char *__path));
41 #define basename(path)  __xpg_basename (path)
42 #endif
43 
44 #include "portab.h"
45 #include "system.h"
46 #include "counter.h"
47 #include "cdrom.h"
48 #include "music_server.h"
49 #include "music_pcm.h"
50 
51 extern void sys_set_signalhandler(int SIG, void (*handler)(int));
52 
53 /*
54    CPU�ѥ�����ޤäƤ��ޤäƤɤ����褦��ʤ��ͤ� :-)
55 
56   �Ȥ���
57 
58    1. �Ȥꤢ���� mpg123 �ʤɤ� �ץ쥤�䡼���Ѱդ��롣
59       esd ��Ȥ��������� Ver 0.59q �ʹߤ�����褦��
60       �ץ졼�䡼�ˤϤ��餫����ѥ����̤��Ƥ�����
61 
62    2. % cat ~/game/kichiku.playlist
63        mpg123 -quite
64        $(HOME)/game/kichiku/mp3/trk02.mp3
65        $(HOME)/game/kichiku/mp3/trk03.mp3
66        $(HOME)/game/kichiku/mp3/trk04.mp3
67        $(HOME)/game/kichiku/mp3/trk05.mp3
68        $(HOME)/game/kichiku/mp3/trk06.mp3
69 
70        �äƤʥե�������Ѱդ��롣( $(HOME)��Ŭ���ˤ����Ƥ� )
71        �����ܤϥץ졼�䡼�Ȥ��Υ��ץ����
72        �����ܰʹߤϥȥ�å��������˥ե������ʤ�٤�
73 
74        �����ܤκǽ��ʸ���� - �ǻϤޤäƤ����� xsystem35 �� audio device ��
75        ή������ (piped play mode) (ex. -mpg123 -quite)
76        player �κ����ե����ޥåȤ� 44kHz,16bit,Stereo�Τ�
77 
78 
79    3 configure �� --enable-cdrom=mp3 ���ɲä���
80 
81    4 �¹Ի����ץ����� -devcd ~/game/kichiku.playlist �Τ褦�˾�Ǻ��������ե���������
82 
83 */
84 
85 static int cdrom_init(char *);
86 static int cdrom_exit();
87 static int cdrom_start(int);
88 static int cdrom_stop();
89 static int cdrom_getPlayingInfo(cd_time *);
90 static int cdrom_setVolumePipe(int vol);
91 static int cdrom_getVolumePipe();
92 
93 #define cdrom cdrom_mp3
94 cdromdevice_t cdrom = {
95 	cdrom_init,
96 	cdrom_exit,
97 	cdrom_start,
98 	cdrom_stop,
99 	cdrom_getPlayingInfo,
100 	NULL,
101 	NULL
102 };
103 
104 #define PLAYLIST_MAX 256
105 #define WHITE " \t\n"
106 #define MAX_ARGS 512
107 
108 static boolean      enabled = FALSE;
109 static char         mp3_player[256];
110 static int          argc;
111 static char         **argv;
112 static char         *playlist[PLAYLIST_MAX];
113 static int          lastindex; // �ǽ��ȥ�å��ֹ�
114 static pid_t        cdpid;   // �����ץ졼�䡼�� pid
115 static int          trackno; // ���߱�����Υȥ�å�
116 static int          counter; // ���ջ���¬���ѥ�����
117 static boolean      pipedplay; // pipe play �⡼�ɤ��ɤ���
118 
119 /*
120   �����ץ졼�䡼�ιԤβ���
121   1. �ǽ��ʸ���� - �Ǥ��ä���硢piped play mode
122   2. �ץ����Ȱ�����ʬΥ (!pipe)
123   3. �ץ���फ��ץ����̾(argv[0])��ʬΥ (!piped)
124 */
125 
player_set(char * buf)126 static void player_set(char *buf) {
127 	char *b;
128 	int i, j;
129 
130 	if (buf[0] == '-') {
131 		pipedplay = TRUE;
132 		buf++;
133 	} else {
134 		pipedplay = FALSE;
135 	}
136 
137 	strncpy(mp3_player, buf, sizeof(mp3_player));
138 	b = mp3_player;
139 
140 	if (!pipedplay) {
141 		/* count arguments */
142 		/* devide argument */
143 		char *tok_buf = NULL;
144 		char *str_buf[MAX_ARGS]; //MAX_ARGS�ʾ�ΰ���������Ȥ���
145 
146 		memset(str_buf, 0, sizeof(char *) * MAX_ARGS);
147 
148 		i = 0;
149 		str_buf[i] = strtok_r(b, WHITE, &tok_buf) ;
150 
151 		if (str_buf[i] == NULL) return;
152 
153 		while (str_buf[i] != NULL){
154 			i++;
155 			if (i >= MAX_ARGS){
156 				return;
157 			}
158 			str_buf[i] = strtok_r(NULL, WHITE, &tok_buf);
159 		}
160 		argv = (char **)malloc(sizeof(char *) * (i + 2));
161 
162 		if (argv == NULL) return;
163 
164 		argc = i;
165 
166 		for (j = 0; j < i; j++) {
167 			argv[j] = str_buf[j];
168 		}
169 		argv[i + 1] = NULL;
170 
171 		/* cut down argv[0] */
172 		argv[0] = basename(argv[0]);
173 	} else {
174 		/*
175 		  pipe ���Ϥ��뤿��˥ե�����̾�θ�� - ��Ĥ���ɬ�פ�
176 		  ����ץ졼��Τ���ˡ��ե�����̾�� %s �ǻ���Ǥ���褦��
177 		  ���뤿��ν��� (by Fumihiko Murata)
178 		*/
179 		int pf = FALSE;
180 
181 		b = mp3_player;
182 		while (*b > 0x1f) {
183 			if (*b == '%' && *(b + 1) == 's') pf = TRUE;
184 			b++;
185 		}
186 		*b = 0;
187 		if (!pf) strcat(b, " \"%s\""); // space ��ޤ�ѥ��ξ��
188 	}
189 }
190 
cdrom_init(char * config_file)191 static int cdrom_init(char *config_file) {
192 	FILE *fp;
193 	char lbuf[256];
194 	int lcnt = 0;
195 	char *s;
196 
197 	if (NULL == (fp = fopen(config_file, "rt"))) return NG;
198 	fgets(lbuf, sizeof(lbuf), fp); lcnt++;
199 
200 	player_set(lbuf);
201 
202 	while (TRUE) {
203 		if (++lcnt >= (PLAYLIST_MAX +2)) {
204 			break;
205 		}
206 		if (!fgets(lbuf, sizeof(lbuf) -1, fp)) {
207 			if (feof(fp)) {
208 				break;
209 			} else {
210 				perror("fgets()");
211 				fclose(fp);
212 				return NG;
213 			}
214 		}
215 		if (NULL == (playlist[lcnt -2] = malloc(strlen(lbuf) + 1))) {
216 			fclose(fp);
217 			return NG;
218 		}
219 		s = lbuf;
220 		while (*s != '\n' && *s != 0) s++;
221 		if (*s == '\n') *s=0;
222 		strcpy(playlist[lcnt - 2], lbuf);
223 	}
224 	lastindex = lcnt -1;
225 	fclose(fp);
226 
227 	trackno = 0;
228 	prv.cd_maxtrk = lastindex;
229 
230 	reset_counter_high(SYSTEMCOUNTER_MP3, 10, 0);
231 	enabled = TRUE;
232 
233 	if (pipedplay) {
234 		cdrom_mp3.setvol = cdrom_setVolumePipe;
235 		cdrom_mp3.getvol = cdrom_getVolumePipe;
236 		NOTICE("cdrom mp3 piped play mode\n");
237 	} else {
238 		NOTICE("cdrom mp3 external player mode\n");
239 	}
240 
241 	return OK;
242 }
243 
cdrom_exit()244 static int cdrom_exit() {
245 	if (enabled) {
246 		cdrom_stop();
247 	}
248 	return OK;
249 }
250 
251 /* �ȥ�å��ֹ� trk �α��� trk = 1~ */
cdrom_start(int trk)252 static int cdrom_start(int trk) {
253 	char cmd_pipe[256];
254 	pid_t pid;
255 
256 	if (!enabled) return 0;
257 
258 	/* �ʿ�����¿��������Բ�*/
259 	if (trk > lastindex) {
260 		return NG;
261 	}
262 
263 	if (pipedplay) {
264 		g_snprintf(cmd_pipe, sizeof(cmd_pipe) -1, mp3_player, playlist[trk -2]);
265 		if (-1 == muspcm_load_pipe(SLOT_CDROMPIPE, cmd_pipe)) {
266 			return NG;
267 		}
268 		muspcm_start(SLOT_CDROMPIPE, 1);
269 		pid = 1; // dummy
270 	} else {
271 		argv[argc] = playlist[trk -2];
272 		argv[argc +1] = NULL;
273 		pid = fork();
274 		if (pid == 0) {
275 			/* child process */
276 			pid_t mine = getpid();
277 			setpgid(mine, mine);
278 			sys_set_signalhandler(SIGTERM, SIG_DFL);
279 			execvp(mp3_player, argv);
280 			perror("execvp");
281 			_exit(-1);
282 		} else if (pid < 0) {
283 			WARNING("fork failed");
284 			return NG;
285 		}
286 	}
287 
288 	cdpid = pid;
289 	trackno = trk;
290 	counter = get_high_counter(SYSTEMCOUNTER_MP3);
291 
292 	return OK;
293 }
294 
295 /* ������� */
cdrom_stop()296 static int cdrom_stop() {
297 	if (!enabled || cdpid == 0) {
298 		return OK;
299 	}
300 
301 	if (!pipedplay) {
302 		int status = 0;
303 		kill(cdpid, SIGTERM);
304 		killpg(cdpid, SIGTERM);
305 		while (0 >= waitpid(cdpid, &status, WNOHANG));
306 	} else {
307 		muspcm_stop(SLOT_CDROMPIPE);
308 	}
309 
310 	cdpid   = 0;
311 	trackno = 0;
312 
313 	return OK;
314 }
315 
316 /* ���߱�����Υȥ�å�����μ��� */
cdrom_getPlayingInfo(cd_time * inf)317 static int cdrom_getPlayingInfo (cd_time *inf) {
318 	int status, cnt, err;
319 
320 	if (!enabled || cdpid == 0) {
321 		goto errout;
322 	}
323 
324 	if (pipedplay) {
325 		cnt = muspcm_getpos(SLOT_CDROMPIPE);
326 		if (cnt == 0) {
327 			goto errout;
328 		}
329 		cnt /= 10;
330 	} else {
331 		if (cdpid == (err = waitpid(cdpid, &status, WNOHANG))) {
332 			cdpid = 0;
333 			goto errout;
334 		}
335 		cnt = get_high_counter(SYSTEMCOUNTER_MP3) - counter;
336 	}
337 
338 	inf->t = trackno;
339 	inf->m = cnt / (60*100); cnt %= (60*100);
340 	inf->s = cnt / 100;      cnt %= 100;
341 	inf->f = (cnt * CD_FPS) / 100;
342 
343 	return OK;
344 
345  errout:
346 	inf->t = inf->m = inf->s = inf->f = 999;
347 	return NG;
348 }
349 
cdrom_setVolumePipe(int vol)350 static int cdrom_setVolumePipe(int vol) {
351 	if (prv.pcm[SLOT_CDROMPIPE] != NULL) {
352 		prv.pcm[SLOT_CDROMPIPE]->vollv = vol;
353 	}
354 	return OK;
355 }
356 
cdrom_getVolumePipe()357 static int cdrom_getVolumePipe() {
358 	if (prv.pcm[SLOT_CDROMPIPE] != NULL) {
359 		return prv.pcm[SLOT_CDROMPIPE]->vollv;
360 	}
361 	return 100;
362 }
363