1 /*
2 * flac123 a command-line flac player
3 * Copyright (C) 2003-2007 Jake Angerman
4 *
5 * This remote.c module heavily based upon:
6 * mpg321 - a fully free clone of mpg123. Copyright (C) 2001 Joe Drew
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #include <sys/time.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include "flac123.h"
28
29 #define BUF_SIZE (PATH_MAX + 5)
30
31 char remote_input_buf[BUF_SIZE];
32
trim_whitespace(char * str)33 static void trim_whitespace(char *str)
34 {
35 char *ptr = str;
36 register int pos = strlen(str)-1;
37
38 while(isspace(ptr[pos]))
39 ptr[pos--] = '\0';
40
41 while(isspace(*ptr))
42 ptr++;
43
44 strncpy(str, ptr, pos+1);
45 }
46
47 /* returns 0 on success (keep decoding), or -1 on QUIT (stop decoding) */
remote_parse_input(void)48 static int remote_parse_input(void)
49 {
50 char input[BUF_SIZE]; /* for filename as well as input and space */
51 char new_remote_input_buf[BUF_SIZE];
52 char *arg, *newline;
53 int numread;
54 int alreadyread;
55 int linelen;
56
57 fd_set fd;
58 struct timeval tv = { 0, 0 };
59 FD_ZERO(&fd);
60 FD_SET(0,&fd);
61
62 alreadyread = strlen (remote_input_buf);
63
64 if (select (1, &fd, NULL, NULL, &tv)) /* return immediately */
65 {
66 if (!(numread = read(0, remote_input_buf + alreadyread, (sizeof(input)-1)-alreadyread)) > 0)
67 {
68 numread = 0; /* should never happen. read() blocks */
69 }
70 } else {
71 numread = 0;
72 }
73
74 remote_input_buf[numread+alreadyread] = '\0';
75
76 if ((newline = strchr(remote_input_buf, '\n')))
77 {
78 *(newline) = '\0';
79 }
80
81 linelen = strlen (remote_input_buf);
82
83 strcpy (input, remote_input_buf);
84 /* input[linelen] = '\0'; */
85 strcpy (new_remote_input_buf, remote_input_buf + linelen + 1);
86 /* don't copy the \0... */
87 strcpy (remote_input_buf, new_remote_input_buf);
88
89 trim_whitespace(input); /* from left and right */
90
91 if (strlen(input) == 0)
92 return 0;
93
94 arg = strchr(input, ' ');
95
96 if (arg)
97 {
98 *(arg++) = '\0'; /* separate command from argument */
99 arg = strdup(arg);
100 trim_whitespace(arg);
101 }
102
103 if (strcasecmp(input, "L") == 0 || strcasecmp(input, "LOAD") == 0)
104 {
105 if (arg)
106 {
107 if (file_info.is_loaded == true)
108 decoder_destructor();
109
110 if (!decoder_constructor(arg))
111 {
112 fprintf(stderr, "@E Error opening %s\n", arg);
113 free(arg);
114 return 0;
115 }
116 }
117 else
118 {
119 fprintf(stderr, "@E Missing argument to '%s'\n", input);
120 return 0;
121 }
122 }
123
124 else if (strcasecmp(input, "J") == 0 || strcasecmp(input, "JUMP") == 0)
125 {
126 if (file_info.is_playing && arg)
127 {
128 /* relative seek */
129 if (arg[0] == '-' || arg[0] == '+')
130 {
131 /* assumption: fixed bit-rate encoding */
132 signed long delta_time = atol(arg);
133 signed long delta_frames = delta_time * file_info.ao_fmt.rate;
134
135 if ((delta_time < 0) && (labs(delta_time) > file_info.elapsed_time))
136 {
137 file_info.elapsed_time = 0;
138 file_info.current_sample = 0;
139 }
140 else if ((delta_time > 0) && (delta_time > file_info.total_time - file_info.elapsed_time))
141 {
142 /* don't do anything */
143 if (arg)
144 free (arg);
145 return 0;
146 }
147 else
148 {
149 file_info.elapsed_time += delta_time;
150 file_info.current_sample += delta_frames;
151 }
152
153 #ifdef LEGACY_FLAC
154 FLAC__file_decoder_seek_absolute(file_info.decoder,
155 file_info.current_sample);
156 #else
157 FLAC__stream_decoder_seek_absolute(file_info.decoder,
158 file_info.current_sample);
159 #endif
160 }
161 /* absolute seek */
162 else
163 {
164 long absolute_time = atol(arg);
165 long absolute_frame = absolute_time * file_info.ao_fmt.rate;
166 file_info.elapsed_time = absolute_time;
167 file_info.current_sample = absolute_frame;
168
169 #ifdef LEGACY_FLAC
170 FLAC__file_decoder_seek_absolute(file_info.decoder, absolute_frame);
171 #else
172 FLAC__stream_decoder_seek_absolute(file_info.decoder, absolute_frame);
173 #endif
174 }
175
176 }
177 else
178 {
179 /* mpg123 does no error checking, so we should emulate that */
180 }
181 }
182
183 else if (strcasecmp(input, "S") == 0 || strcasecmp(input, "STOP") == 0)
184 {
185 if (file_info.is_loaded == true)
186 {
187 fprintf(stderr, "@P 0\n");
188 decoder_destructor();
189 }
190 }
191
192 else if (strcasecmp(input, "V") == 0 || strcasecmp(input, "VOLUME") == 0)
193 {
194 if (arg)
195 {
196 scale = atof(arg);
197 fprintf(stderr, "@V %f\n", scale);
198 }
199 }
200
201 else if (strcasecmp(input, "P") == 0 || strcasecmp(input, "PAUSE") == 0)
202 {
203 if (file_info.is_loaded == true)
204 {
205 if (file_info.is_playing == true)
206 {
207 file_info.is_playing = false;
208 fprintf(stderr, "@P 1\n");
209 }
210 else
211 {
212 file_info.is_playing = true;
213 fprintf(stderr, "@P 2\n");
214 }
215 }
216 }
217
218 else if (strcasecmp(input, "Q") == 0 || strcasecmp(input, "QUIT") == 0)
219 {
220 if (arg)
221 free(arg);
222
223 if (file_info.is_loaded)
224 decoder_destructor();
225
226 return -1;
227 }
228
229 else
230 {
231 fprintf(stderr, "@E Unknown command '%s'\n", input);
232 }
233
234 if (arg)
235 free(arg);
236
237 return 0;
238 }
239
remote_get_input_wait(void)240 int remote_get_input_wait(void)
241 {
242 fd_set fd;
243 FD_ZERO(&fd);
244 FD_SET(0,&fd);
245
246 if (strlen(remote_input_buf) == 0)
247 {
248 select(1, &fd, NULL, NULL, NULL); /* block indefinitely */
249 }
250
251 return remote_parse_input();
252 }
253
remote_get_input_nowait(void)254 int remote_get_input_nowait(void)
255 {
256 fd_set fd;
257 struct timeval tv = { 0, 0 };
258 FD_ZERO(&fd);
259 FD_SET(0,&fd);
260
261 if (strlen(remote_input_buf) == 0)
262 {
263 if (select(1, &fd, NULL, NULL, &tv)) /* return immediately */
264 return remote_parse_input();
265 else
266 return 0;
267 }
268 else
269 {
270 return remote_parse_input();
271 }
272 }
273
274