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(&current_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