1 /*
2 * flac123 a command-line flac player
3 * Copyright (C) 2003-2007 Jake Angerman
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <popt.h>
21 #include <string.h>
22 #include <sys/time.h>
23 #include <signal.h>
24 #include "flac123.h"
25 #include "version.h"
26
27 file_info_struct file_info = { NULL, {0,0,0,0}, {0,0,0,0}, NULL, "", 0,0,0,0, false };
28
29 static int ao_output_id;
30
31 typedef struct {
32 char *driver;
33 char *buffer_size;
34 char *wavfile;
35 int remote;
36 int quiet;
37 int version;
38 } cli_var_struct;
39
40 cli_var_struct cli_args = { NULL, NULL, 0, 0, 0 };
41
42 struct poptOption cli_options[] = {
43 /* longName, shortName, argInfo, arg, val, descrip, argDescrip */
44 { "driver", 'd', POPT_ARG_STRING, (void *)&(cli_args.driver), 0, "set libao output driver (oss, esd, arts, macosx, etc). Default is " AUDIO_DEFAULT, NULL },
45 { "wav", 'w', POPT_ARG_STRING, (void *)&(cli_args.wavfile), 0, "send output to wav file (use --wav=- and -q for stdout)", "FILENAME" },
46 { "remote", 'R', POPT_ARG_NONE, (void *)&(cli_args.remote), 0, "set remote mode for programmatic control", NULL },
47 { "buffer-size", 'b', POPT_ARG_STRING, (void *)&(cli_args.buffer_size), 0, "buffer size", NULL },
48 { "quiet", 'q', POPT_ARG_NONE, (void *)&(cli_args.quiet), 0, "suppress text output", NULL },
49 { "version", 'v', POPT_ARG_NONE,(void *)&(cli_args.version),0,"version/copyright info",NULL},
50 POPT_AUTOHELP
51 { 0, 0, 0, 0, 0, NULL, NULL }
52 };
53
54 static void play_file(const char *);
55 static void play_remote_file(void);
56 #ifdef LEGACY_FLAC
57 void flac_error_hdl(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *);
58 void flac_metadata_hdl(const FLAC__FileDecoder *, const FLAC__StreamMetadata *, void *);
59 FLAC__StreamDecoderWriteStatus flac_write_hdl(const FLAC__FileDecoder *,
60 const FLAC__Frame *, const FLAC__int32 * const buf[], void *);
61 #else
62 void flac_error_hdl(const FLAC__StreamDecoder *, FLAC__StreamDecoderErrorStatus, void *);
63 void flac_metadata_hdl(const FLAC__StreamDecoder *, const FLAC__StreamMetadata *, void *);
64 FLAC__StreamDecoderWriteStatus flac_write_hdl(const FLAC__StreamDecoder *,
65 const FLAC__Frame *, const FLAC__int32 * const buf[], void *);
66 #endif
67
68 static void signal_handler(int);
69 static int quit_now = 0;
70 static int interrupted = 0;
71
72 float scale = 1;
73 ao_option **ao_options = NULL;
74
main(int argc,const char ** argv)75 int main(int argc, const char **argv)
76 {
77 int tmp;
78 poptContext pc;
79 const char *filename;
80
81 pc = poptGetContext("flac123", argc, argv, cli_options, 0);
82 poptSetOtherOptionHelp(pc, "[OPTIONS] FILES...");
83 while (poptGetNextOpt(pc) >= 0)
84 {
85 }
86
87 if (cli_args.version) {
88 printf("flac123 version %s, maintainer Hans Oesterholt, (c) 2012 GPLv2\n",FLAC123_VERSION);
89 exit(0);
90 }
91
92 if (!(cli_args.quiet || cli_args.remote)) {
93 printf("flac123 version %s 'flac123 --help' for more info\n", FLAC123_VERSION);
94 }
95
96 ao_initialize();
97
98 ao_options = malloc(1024);
99 *ao_options = NULL;
100 if (cli_args.buffer_size)
101 ao_append_option(ao_options, "buffer_size", cli_args.buffer_size);
102
103 if (! cli_args.wavfile) {
104 if (cli_args.driver) {
105 ao_output_id = ao_driver_id(cli_args.driver);
106 if(ao_output_id < 0) {
107 fprintf(stderr, "Error identifying libao driver %s\n", cli_args.driver);
108 ao_output_id = ao_default_driver_id();
109 }
110 } else {
111 ao_output_id = ao_default_driver_id();
112 }
113
114 if (ao_output_id < 0) {
115 fprintf(stderr, "No fallback libao driver found, exiting.\n");
116 ao_shutdown();
117 exit(1);
118 }
119 }
120
121 if (cli_args.remote)
122 {
123 setvbuf(stdout, NULL, _IONBF, 0);
124 play_remote_file();
125 }
126 else
127 {
128 if (signal(SIGINT, signal_handler) == SIG_ERR)
129 fprintf(stderr, "signal handler setup failed.\n");
130
131 do {
132 if (filename = poptGetArg(pc))
133 play_file(filename);
134 } while (filename != NULL && !quit_now);
135 }
136
137 if (file_info.ao_dev)
138 ao_close(file_info.ao_dev);
139 ao_shutdown();
140
141 return 0;
142 }
143
print_file_info(const char * filename)144 static void print_file_info(const char *filename)
145 {
146 FLAC__bool got_vorbis = get_vorbis_comments(filename);
147
148 if (cli_args.remote)
149 {
150 if (got_vorbis)
151 {
152 fprintf(stderr, "@I ID3:%s%s%s%s%s%s\n",
153 file_info.title,
154 file_info.artist,
155 file_info.album,
156 file_info.year,
157 file_info.comment,
158 file_info.genre
159 );
160 }
161 else
162 {
163 /* print filename without suffix */
164 char *dupe = strdup(filename);
165 char *dot = strrchr(dupe, '.');
166
167 if (dot && dot == strstr(dupe, ".flac"))
168 *dot = '\0';
169
170 fprintf(stderr, "@I %s\n", dupe);
171 free(dupe);
172 }
173 }
174 else if (!cli_args.quiet)
175 {
176 printf("\n"
177 "Title : %s Artist: %s\n"
178 "Album : %s Year : %s\n"
179 "Comment: %s Genre : %s\n",
180 file_info.title, file_info.artist,
181 file_info.album, file_info.year,
182 file_info.comment, file_info.genre);
183 printf("\nPlaying FLAC stream from %s\n",
184 strncasecmp(filename, "http://", 7) != 0 &&
185 strchr(filename, '/') ? strrchr(filename, '/')+1 : filename);
186 printf("%d bit, %d Hz, %d channels, %d total samples, "
187 "%.2f total seconds\n",
188 file_info.sam_fmt.bits, file_info.ao_fmt.rate,
189 file_info.ao_fmt.channels, file_info.total_samples,
190 file_info.total_time);
191 }
192 }
193
decoder_constructor(const char * filename)194 FLAC__bool decoder_constructor(const char *filename)
195 {
196 int len = strlen(filename);
197 int max_len = len < PATH_MAX ? len : PATH_MAX-1;
198 static ao_sample_format previous_bitrate;
199 static int first_time = true;
200
201 file_info.filename[max_len] = '\0';
202 strncpy(file_info.filename, filename, max_len);
203
204 memset(file_info.title, ' ', VORBIS_TAG_LEN);
205 file_info.title[VORBIS_TAG_LEN] = '\0';
206 memset(file_info.artist, ' ', VORBIS_TAG_LEN);
207 file_info.artist[VORBIS_TAG_LEN] = '\0';
208 memset(file_info.album, ' ', VORBIS_TAG_LEN);
209 file_info.album[VORBIS_TAG_LEN] = '\0';
210 memset(file_info.genre, ' ', VORBIS_TAG_LEN);
211 file_info.genre[VORBIS_TAG_LEN] = '\0';
212 memset(file_info.comment, ' ', VORBIS_TAG_LEN);
213 file_info.comment[VORBIS_TAG_LEN] = '\0';
214 memset(file_info.year, ' ', VORBIS_YEAR_LEN);
215 file_info.year[VORBIS_YEAR_LEN] = '\0';
216
217 /* create and initialize flac decoder object */
218 #ifdef LEGACY_FLAC
219 file_info.decoder = FLAC__file_decoder_new();
220 FLAC__file_decoder_set_md5_checking(file_info.decoder, true);
221 FLAC__file_decoder_set_filename(file_info.decoder, filename);
222
223 FLAC__file_decoder_set_write_callback(file_info.decoder,
224 flac_write_hdl);
225 FLAC__file_decoder_set_metadata_callback(file_info.decoder,
226 flac_metadata_hdl);
227 FLAC__file_decoder_set_error_callback(file_info.decoder,
228 flac_error_hdl);
229 FLAC__file_decoder_set_client_data(file_info.decoder,
230 (void *)&file_info);
231
232 /* read metadata */
233 if ((FLAC__file_decoder_init(file_info.decoder) != FLAC__FILE_DECODER_OK)
234 || (!FLAC__file_decoder_process_until_end_of_metadata(file_info.decoder)))
235 {
236 FLAC__file_decoder_delete(file_info.decoder);
237 return false;
238 }
239 #else
240 file_info.decoder = FLAC__stream_decoder_new();
241 FLAC__stream_decoder_set_md5_checking(file_info.decoder, true);
242
243 /* read metadata */
244 if ((FLAC__stream_decoder_init_file(file_info.decoder, filename, flac_write_hdl, flac_metadata_hdl, flac_error_hdl, (void *)&file_info) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
245 || (!FLAC__stream_decoder_process_until_end_of_metadata(file_info.decoder)))
246 {
247 FLAC__stream_decoder_delete(file_info.decoder);
248 return false;
249 }
250 #endif
251
252 /* open libao output device */
253 if (cli_args.wavfile) {
254 if (!(file_info.ao_dev = ao_open_file(ao_driver_id("wav"), cli_args.wavfile, /*overwrite*/ 1, &(file_info.ao_fmt), NULL)))
255 {
256 fprintf(stderr, "Error opening wav file %s\n", cli_args.wavfile);
257 #ifdef LEGACY_FLAC
258 FLAC__file_decoder_delete(file_info.decoder);
259 #else
260 FLAC__stream_decoder_delete(file_info.decoder);
261 #endif
262 return false;
263 }
264 }
265 else if (first_time) {
266 if (!(file_info.ao_dev = ao_open_live(ao_output_id, &(file_info.ao_fmt), *ao_options)))
267 {
268 fprintf(stderr, "Error opening ao device %d\n", ao_output_id);
269 #ifdef LEGACY_FLAC
270 FLAC__file_decoder_delete(file_info.decoder);
271 #else
272 FLAC__stream_decoder_delete(file_info.decoder);
273 #endif
274 return false;
275 }
276 }
277 else if (previous_bitrate.bits != file_info.ao_fmt.bits ||
278 previous_bitrate.rate != file_info.ao_fmt.rate ||
279 previous_bitrate.channels != file_info.ao_fmt.channels)
280 {
281 /* close the ao_device and re-open */
282 ao_close(file_info.ao_dev);
283 if (!(file_info.ao_dev = ao_open_live(ao_output_id, &(file_info.ao_fmt), *ao_options)))
284 {
285 fprintf(stderr, "Error opening ao device %d\n", ao_output_id);
286 #ifdef LEGACY_FLAC
287 FLAC__file_decoder_delete(file_info.decoder);
288 #else
289 FLAC__stream_decoder_delete(file_info.decoder);
290 #endif
291 return false;
292 }
293 }
294
295 print_file_info(filename);
296
297 previous_bitrate.bits = file_info.ao_fmt.bits;
298 previous_bitrate.rate = file_info.ao_fmt.rate;
299 previous_bitrate.channels = file_info.ao_fmt.channels;
300
301 first_time = false;
302 file_info.is_loaded = true;
303 file_info.is_playing = true;
304
305 return true;
306 }
307
decoder_destructor(void)308 void decoder_destructor(void)
309 {
310 #ifdef LEGACY_FLAC
311 FLAC__file_decoder_finish(file_info.decoder);
312 FLAC__file_decoder_delete(file_info.decoder);
313 #else
314 FLAC__stream_decoder_finish(file_info.decoder);
315 FLAC__stream_decoder_delete(file_info.decoder);
316 #endif
317 file_info.is_loaded = false;
318 file_info.is_playing = false;
319 file_info.filename[0] = '\0';
320 }
321
play_file(const char * filename)322 static void play_file(const char *filename)
323 {
324 if (!decoder_constructor(filename))
325 {
326 fprintf(stderr, "Error opening %s\n", filename);
327 return;
328 }
329
330 #ifdef LEGACY_FLAC
331 while (FLAC__file_decoder_process_single(file_info.decoder) == true &&
332 FLAC__file_decoder_get_state(file_info.decoder) ==
333 FLAC__FILE_DECODER_OK && !interrupted)
334 #else
335 while (FLAC__stream_decoder_process_single(file_info.decoder) == true &&
336 FLAC__stream_decoder_get_state(file_info.decoder) <
337 FLAC__STREAM_DECODER_END_OF_STREAM && !interrupted)
338 #endif
339 {
340 }
341 interrupted = 0; /* more accurate feedback if placed after loop */
342
343 decoder_destructor();
344 }
345
play_remote_file(void)346 static void play_remote_file(void)
347 {
348 int status = 0;
349
350 fprintf(stderr, "@R FLAC123\n");
351
352 while (status == 0)
353 {
354 if (file_info.is_playing == true)
355 {
356 #ifdef LEGACY_FLAC
357 if (FLAC__file_decoder_get_state(file_info.decoder) ==
358 FLAC__FILE_DECODER_END_OF_FILE)
359 #else
360 if (FLAC__stream_decoder_get_state(file_info.decoder) ==
361 FLAC__STREAM_DECODER_END_OF_STREAM)
362 #endif
363 {
364 decoder_destructor();
365 fprintf(stderr, "@P 0\n");
366 }
367 #ifdef LEGACY_FLAC
368 else if (!FLAC__file_decoder_process_single(file_info.decoder))
369 #else
370 else if (!FLAC__stream_decoder_process_single(file_info.decoder))
371 #endif
372 {
373 fprintf(stderr, "error decoding single frame!\n");
374 }
375
376 /* get the next command, no wait */
377 status = remote_get_input_nowait();
378 }
379 else
380 {
381 /* get the next command, wait */
382 status = remote_get_input_wait();
383 }
384 }
385 }
386
387 #ifdef LEGACY_FLAC
flac_error_hdl(const FLAC__FileDecoder * dec,FLAC__StreamDecoderErrorStatus status,void * data)388 void flac_error_hdl(const FLAC__FileDecoder *dec,
389 FLAC__StreamDecoderErrorStatus status, void *data)
390 #else
391 void flac_error_hdl(const FLAC__StreamDecoder *dec,
392 FLAC__StreamDecoderErrorStatus status, void *data)
393 #endif
394 {
395 fprintf(stderr, "error handler called!\n");
396 }
397
398 #ifdef LEGACY_FLAC
flac_metadata_hdl(const FLAC__FileDecoder * dec,const FLAC__StreamMetadata * meta,void * data)399 void flac_metadata_hdl(const FLAC__FileDecoder *dec,
400 const FLAC__StreamMetadata *meta, void *data)
401 #else
402 void flac_metadata_hdl(const FLAC__StreamDecoder *dec,
403 const FLAC__StreamMetadata *meta, void *data)
404 #endif
405 {
406 file_info_struct *p = (file_info_struct *) data;
407
408 if(meta->type == FLAC__METADATA_TYPE_STREAMINFO) {
409 p->sam_fmt.bits = p->ao_fmt.bits = meta->data.stream_info.bits_per_sample;
410 #ifdef DARWIN
411 if (meta->data.stream_info.bits_per_sample == 8 && !cli_args.wavfile)
412 p->ao_fmt.bits = 16;
413 #endif
414 p->ao_fmt.rate = meta->data.stream_info.sample_rate;
415 p->ao_fmt.channels = meta->data.stream_info.channels;
416 p->ao_fmt.byte_format = AO_FMT_NATIVE;
417 FLAC__ASSERT(meta->data.stream_info.total_samples <
418 0x100000000); /* we can handle < 4 gigasamples */
419 p->total_samples = (unsigned)
420 (meta->data.stream_info.total_samples & 0xffffffff);
421 p->current_sample = 0;
422 p->total_time = (((float) p->total_samples) / p->ao_fmt.rate);
423 p->elapsed_time = 0;
424 }
425 }
426
427 #ifdef LEGACY_FLAC
flac_write_hdl(const FLAC__FileDecoder * dec,const FLAC__Frame * frame,const FLAC__int32 * const buf[],void * data)428 FLAC__StreamDecoderWriteStatus flac_write_hdl(const FLAC__FileDecoder *dec,
429 const FLAC__Frame *frame,
430 const FLAC__int32 * const buf[],
431 void *data)
432 #else
433 FLAC__StreamDecoderWriteStatus flac_write_hdl(const FLAC__StreamDecoder *dec,
434 const FLAC__Frame *frame,
435 const FLAC__int32 * const buf[],
436 void *data)
437 #endif
438 {
439 int sample, channel, i;
440 uint_32 samples = frame->header.blocksize;
441 file_info_struct *p = (file_info_struct *) data;
442 uint_32 decoded_size = frame->header.blocksize * frame->header.channels
443 * (p->ao_fmt.bits / 8);
444 static uint_8 aobuf[FLAC__MAX_BLOCK_SIZE * FLAC__MAX_CHANNELS *
445 sizeof(uint_32)]; /*oink!*/
446 uint_16 *u16aobuf = (uint_16 *) aobuf;
447 uint_8 *u8aobuf = (uint_8 *) aobuf;
448 float elapsed, remaining_time;
449
450 if (p->sam_fmt.bits == 8) {
451 for (sample = i = 0; sample < samples; sample++) {
452 for(channel = 0; channel < frame->header.channels; channel++,i++) {
453 if (cli_args.wavfile) {
454 /* 8 bit wav data is unsigned */
455 u8aobuf[i] = (uint_8)(buf[channel][sample] + 0x80);
456 } else {
457 #ifdef DARWIN
458 /* macosx libao expects 16 bit samples */
459 u16aobuf[i] = (uint_16)(buf[channel][sample] << 8);
460 #else
461 u8aobuf[i] = buf[channel][sample];
462 #endif
463 }
464 }
465 }
466 } else if (p->sam_fmt.bits == 16) {
467 for (sample = i = 0; sample < samples; sample++) {
468 for(channel = 0; channel < frame->header.channels; channel++,i++) {
469 u16aobuf[i] = (uint_16)(buf[channel][sample] * scale);
470 }
471 }
472 }
473
474 ao_play(p->ao_dev, aobuf, decoded_size);
475
476 p->current_sample += samples;
477 elapsed = ((float) samples) / frame->header.sample_rate;
478 p->elapsed_time += elapsed;
479 if ((remaining_time = p->total_time - p->elapsed_time) < 0)
480 remaining_time = 0;
481
482 if (cli_args.remote)
483 {
484 fprintf(stderr, "@F %u %u %.2f %.2f\n",
485 p->current_sample,
486 p->total_samples > 0 ?
487 p->total_samples - p->current_sample : p->current_sample,
488 p->elapsed_time,
489 remaining_time);
490 }
491
492 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
493 }
494
signal_handler(int sig)495 void signal_handler(int sig) {
496 static struct timeval last_time = { 0, 0 };
497 struct timeval current_time;
498
499 gettimeofday(¤t_time, /*no timezone*/ NULL);
500
501 if (sig == SIGINT) {
502 interrupted = 1;
503
504 if (current_time.tv_sec - last_time.tv_sec < 1) {
505 /* multiple SIGINT received in short succession */
506 quit_now = 1;
507 }
508
509 last_time.tv_sec = current_time.tv_sec;
510 last_time.tv_usec = current_time.tv_usec;
511 }
512 }
513