1 /* ogg123.c by Kenneth Arnold <kcarnold-xiph@arnoldnet.net> */
2 /* Maintained by Stan Seibert <volsung@xiph.org>, Monty <monty@xiph.org> */
3
4 /********************************************************************
5 * *
6 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
7 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
8 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
9 * PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
10 * *
11 * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2005 *
12 * by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS *
13 * http://www.xiph.org/ *
14 * *
15 ********************************************************************
16
17 last mod: $Id$
18
19 ********************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <sys/types.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <time.h>
31 #include <getopt.h>
32 #include <signal.h>
33 #include <unistd.h>
34 #include <sys/time.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <locale.h>
38
39 #include "audio.h"
40 #include "buffer.h"
41 #include "callbacks.h"
42 #include "cfgfile_options.h"
43 #include "cmdline_options.h"
44 #include "format.h"
45 #include "transport.h"
46 #include "status.h"
47 #include "playlist.h"
48 #include "compat.h"
49 #include "remote.h"
50
51 #include "ogg123.h"
52 #include "i18n.h"
53
54 extern int exit_status; /* from status.c */
55
56 void play (const char *source_string);
57
58 #define PRIMAGIC (2*2*2*2*3*3*3*5*7)
59 /* take buffer out of the data segment, not the stack */
60 #define AUDIO_CHUNK_SIZE ((16384 + PRIMAGIC - 1)/ PRIMAGIC * PRIMAGIC)
61 static unsigned char convbuffer[AUDIO_CHUNK_SIZE];
62 static int convsize = AUDIO_CHUNK_SIZE;
63
64 ogg123_options_t options;
65 stat_format_t *stat_format;
66 static buf_t *audio_buffer=NULL;
67
68 static audio_play_arg_t audio_play_arg;
69
70
71 /* ------------------------- config file options -------------------------- */
72
73 /* This macro is used to create some dummy variables to hold default values
74 for the options. */
75 #define INIT(type, value) static type type##_##value = value
76 INIT(int, 0);
77
78 file_option_t file_opts[] = {
79 /* found, name, description, type, ptr, default */
80 {0, "default_device", N_("default output device"), opt_type_string,
81 &options.default_device, NULL},
82 {0, "shuffle", N_("shuffle playlist"), opt_type_bool,
83 &options.shuffle, &int_0},
84 {0, "repeat", N_("repeat playlist forever"), opt_type_bool,
85 &options.repeat, &int_0},
86 {0, NULL, NULL, 0, NULL, NULL}
87 };
88
89
90 /* Flags set by the signal handler to control the threads */
91 signal_request_t sig_request = {0, 0, 0, 0, 0};
92
93
94 /* ------------------------------- signal handler ------------------------- */
95
96
signal_handler(int signo)97 void signal_handler (int signo)
98 {
99 struct timeval tv;
100 ogg_int64_t now;
101 switch (signo) {
102 case SIGINT:
103
104 gettimeofday(&tv, 0);
105
106 /* Units of milliseconds (need the cast to force 64 arithmetics) */
107 now = (ogg_int64_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
108
109 if ( (now - sig_request.last_ctrl_c) <= options.delay)
110 sig_request.exit = 1;
111 else
112 sig_request.skipfile = 1;
113
114 sig_request.cancel = 1;
115 sig_request.last_ctrl_c = now;
116 break;
117
118 case SIGTERM:
119 sig_request.exit = 1;
120 break;
121
122 case SIGTSTP:
123 sig_request.pause = 1;
124 /* buffer_Pause (Options.outputOpts.buffer);
125 buffer_WaitForPaused (Options.outputOpts.buffer);
126 }
127 if (Options.outputOpts.devicesOpen == 0) {
128 close_audio_devices (Options.outputOpts.devices);
129 Options.outputOpts.devicesOpen = 0;
130 }
131 */
132 /* open_audio_devices();
133 if (Options.outputOpts.buffer) {
134 buffer_Unpause (Options.outputOpts.buffer);
135 }
136 */
137 break;
138
139 case SIGCONT:
140 break; /* Don't need to do anything special to resume */
141 }
142 }
143
144 /* -------------------------- util functions ---------------------------- */
145
options_init(ogg123_options_t * opts)146 void options_init (ogg123_options_t *opts)
147 {
148 opts->verbosity = 2;
149 opts->shuffle = 0;
150 opts->delay = 500;
151 opts->nth = 1;
152 opts->ntimes = 1;
153 opts->seekoff = 0.0;
154 opts->endpos = -1.0; /* Mark as unset */
155 opts->seekmode = DECODER_SEEK_NONE;
156 opts->buffer_size = 128 * 1024;
157 opts->prebuffer = 0.0f;
158 opts->input_buffer_size = 64 * 1024;
159 opts->input_prebuffer = 50.0f;
160 opts->default_device = NULL;
161
162 opts->status_freq = 10.0;
163 opts->playlist = NULL;
164 opts->remote = 0;
165 opts->repeat = 0;
166
167 }
168
strtotime(char * s)169 double strtotime(char *s)
170 {
171 double time;
172
173 time = strtod(s, &s);
174
175 while (*s == ':')
176 time = 60 * time + strtod(s + 1, &s);
177
178 return time;
179 }
180
set_seek_opt(ogg123_options_t * ogg123_opts,char * buf)181 void set_seek_opt(ogg123_options_t *ogg123_opts, char *buf) {
182
183 char *b = buf;
184
185 /* skip spaces */
186 while (*b && (*b == ' ')) b++;
187
188 if (*b == '-') {
189 /* relative seek back */
190 ogg123_opts->seekoff = -1 * strtotime(b+1);
191 ogg123_opts->seekmode = DECODER_SEEK_CUR;
192 } else
193 if (*b == '+') {
194 /* relative seek forward */
195 ogg123_opts->seekoff = strtotime(b+1);
196 ogg123_opts->seekmode = DECODER_SEEK_CUR;
197 } else {
198 /* absolute seek */
199 ogg123_opts->seekoff = strtotime(b);
200 ogg123_opts->seekmode = DECODER_SEEK_START;
201 }
202 }
203
handle_seek_opt(ogg123_options_t * options,decoder_t * decoder,format_t * format)204 int handle_seek_opt(ogg123_options_t *options, decoder_t *decoder, format_t *format) {
205
206 float pos=decoder->format->statistics(decoder)->current_time;
207
208 /* this functions handles a seek request. It prevents seeking out
209 of band, i.e. before the beginning or after the end. Instead,
210 it seeks to the start or near-end resp. */
211
212 if (options->seekmode != DECODER_SEEK_NONE) {
213
214 if (options->seekmode == DECODER_SEEK_START) {
215 pos = options->seekoff;
216 } else {
217 pos += options->seekoff;
218 }
219
220 if (pos < 0) {
221 pos = 0;
222 }
223
224 if (pos > decoder->format->statistics(decoder)->total_time) {
225 /* seek to almost the end of the stream */
226 pos = decoder->format->statistics(decoder)->total_time - 0.01;
227 }
228
229 if (!format->seek(decoder, pos, DECODER_SEEK_START)) {
230 status_error(_("Could not skip to %f in audio stream."), options->seekoff);
231 #if 0
232 /* Handle this fatally -- kill the audio thread */
233 if (audio_buffer != NULL)
234 buffer_thread_kill(audio_buffer);
235 #endif
236 }
237 }
238
239 options->seekmode = DECODER_SEEK_NONE;
240
241 return 1;
242 }
243
244 /* This function selects which statistics to display for our
245 particular configuration. This does not have anything to do with
246 verbosity, but rather with which stats make sense to display. */
select_stats(stat_format_t * stats,ogg123_options_t * opts,data_source_t * source,decoder_t * decoder,buf_t * audio_buffer)247 void select_stats (stat_format_t *stats, ogg123_options_t *opts,
248 data_source_t *source, decoder_t *decoder,
249 buf_t *audio_buffer)
250 {
251 data_source_stats_t *data_source_stats;
252
253 if (audio_buffer != NULL) {
254 /* Turn on output buffer stats */
255 stats[8].enabled = 1; /* Fill */
256 stats[9].enabled = 1; /* State */
257 } else {
258 stats[8].enabled = 0;
259 stats[9].enabled = 0;
260 }
261
262 data_source_stats = source->transport->statistics(source);
263 if (data_source_stats->input_buffer_used) {
264 /* Turn on input buffer stats */
265 stats[6].enabled = 1; /* Fill */
266 stats[7].enabled = 1; /* State */
267 } else {
268 stats[6].enabled = 0;
269 stats[7].enabled = 0;
270 }
271 free(data_source_stats);
272
273 /* Assume we need total time display, and let display_statistics()
274 determine at what point it should be turned off during playback */
275 stats[2].enabled = 1; /* Remaining playback time */
276 stats[3].enabled = 1; /* Total playback time */
277 }
278
279
280 /* Handles printing statistics depending upon whether or not we have
281 buffering going on */
display_statistics(stat_format_t * stat_format,buf_t * audio_buffer,data_source_t * source,decoder_t * decoder)282 void display_statistics (stat_format_t *stat_format,
283 buf_t *audio_buffer,
284 data_source_t *source,
285 decoder_t *decoder)
286 {
287 print_statistics_arg_t *pstats_arg;
288 buffer_stats_t *buffer_stats;
289
290 pstats_arg = new_print_statistics_arg(stat_format,
291 source->transport->statistics(source),
292 decoder->format->statistics(decoder));
293
294 if (options.remote) {
295
296 /* Display statistics via the remote interface */
297 remote_time(pstats_arg->decoder_statistics->current_time,
298 pstats_arg->decoder_statistics->total_time);
299
300 } else {
301
302 /* Disable/Enable statistics as needed */
303
304 if (pstats_arg->decoder_statistics->total_time <
305 pstats_arg->decoder_statistics->current_time) {
306 stat_format[2].enabled = 0; /* Remaining playback time */
307 stat_format[3].enabled = 0; /* Total playback time */
308 }
309
310 if (pstats_arg->data_source_statistics->input_buffer_used) {
311 stat_format[6].enabled = 1; /* Input buffer fill % */
312 stat_format[7].enabled = 1; /* Input buffer state */
313 }
314
315 if (audio_buffer) {
316 /* Place a status update into the buffer */
317 buffer_append_action_at_end(audio_buffer,
318 &print_statistics_action,
319 pstats_arg);
320
321 /* And if we are not playing right now, do an immediate
322 update just the output buffer */
323 buffer_stats = buffer_statistics(audio_buffer);
324 if (buffer_stats->paused || buffer_stats->prebuffering) {
325 pstats_arg = new_print_statistics_arg(stat_format,
326 NULL,
327 NULL);
328 print_statistics_action(audio_buffer, pstats_arg);
329 }
330 free(buffer_stats);
331
332 } else
333 print_statistics_action(NULL, pstats_arg);
334 }
335 }
336
337
display_statistics_quick(stat_format_t * stat_format,buf_t * audio_buffer,data_source_t * source,decoder_t * decoder)338 void display_statistics_quick (stat_format_t *stat_format,
339 buf_t *audio_buffer,
340 data_source_t *source,
341 decoder_t *decoder)
342 {
343 print_statistics_arg_t *pstats_arg;
344
345 pstats_arg = new_print_statistics_arg(stat_format,
346 source->transport->statistics(source),
347 decoder->format->statistics(decoder));
348
349 if (audio_buffer) {
350 print_statistics_action(audio_buffer, pstats_arg);
351 } else
352 print_statistics_action(NULL, pstats_arg);
353 }
354
current_time(decoder_t * decoder)355 double current_time (decoder_t *decoder)
356 {
357 decoder_stats_t *stats;
358 double ret;
359
360 stats = decoder->format->statistics(decoder);
361 ret = stats->current_time;
362
363 free(stats);
364
365 return ret;
366 }
367
print_audio_devices_info(audio_device_t * d)368 void print_audio_devices_info(audio_device_t *d)
369 {
370 ao_info *info;
371
372 while (d != NULL) {
373 info = ao_driver_info(d->driver_id);
374
375 status_message(2, _("\nAudio Device: %s"), info->name);
376 status_message(3, _("Author: %s"), info->author);
377 status_message(3, _("Comments: %s"), info->comment);
378 status_message(2, "");
379
380 d = d->next_device;
381 }
382
383 }
384
385
386 /* --------------------------- main code -------------------------------- */
387
388
389
main(int argc,char ** argv)390 int main(int argc, char **argv)
391 {
392 int optind;
393 char **playlist_array;
394 int items;
395 struct stat stat_buf;
396 int i;
397
398 setlocale(LC_ALL, "");
399 bindtextdomain(PACKAGE, LOCALEDIR);
400 textdomain(PACKAGE);
401
402 ao_initialize();
403 stat_format = stat_format_create();
404 options_init(&options);
405 file_options_init(file_opts);
406
407 parse_std_configs(file_opts);
408 options.playlist = playlist_create();
409 optind = parse_cmdline_options(argc, argv, &options, file_opts);
410
411 audio_play_arg.devices = options.devices;
412 audio_play_arg.stat_format = stat_format;
413
414 /* Add remaining arguments to playlist */
415 for (i = optind; i < argc; i++) {
416 if (stat(argv[i], &stat_buf) == 0) {
417
418 if (S_ISDIR(stat_buf.st_mode)) {
419 if (playlist_append_directory(options.playlist, argv[i]) == 0)
420 fprintf(stderr,
421 _("WARNING: Could not read directory %s.\n"), argv[i]);
422 } else {
423 playlist_append_file(options.playlist, argv[i]);
424 }
425 } else /* If we can't stat it, it might be a non-disk source */
426 playlist_append_file(options.playlist, argv[i]);
427
428
429 }
430
431
432 /* Do we have anything left to play? */
433 if (playlist_length(options.playlist) == 0) {
434 cmdline_usage();
435 exit(1);
436 } else {
437 playlist_array = playlist_to_array(options.playlist, &items);
438 playlist_destroy(options.playlist);
439 options.playlist = NULL;
440 }
441
442 /* Don't use status_message until after this point! */
443 status_init(options.verbosity);
444
445 print_audio_devices_info(options.devices);
446
447
448 /* Setup buffer */
449 if (options.buffer_size > 0) {
450 /* Keep sample size alignment for surround sound with up to 10 channels */
451 options.buffer_size = (options.buffer_size + PRIMAGIC - 1) / PRIMAGIC * PRIMAGIC;
452 audio_buffer = buffer_create(options.buffer_size,
453 options.buffer_size * options.prebuffer / 100,
454 audio_play_callback, &audio_play_arg,
455 AUDIO_CHUNK_SIZE);
456 if (audio_buffer == NULL) {
457 status_error(_("Error: Could not create audio buffer.\n"));
458 exit(1);
459 }
460 } else
461 audio_buffer = NULL;
462
463
464 /* Setup signal handlers and callbacks */
465
466 signal (SIGINT, signal_handler);
467 signal (SIGTSTP, signal_handler);
468 signal (SIGCONT, signal_handler);
469 signal (SIGTERM, signal_handler);
470
471 if (options.remote) {
472 /* run the mainloop for the remote interface */
473 remote_mainloop();
474
475 } else {
476
477 do {
478 /* Shuffle playlist */
479 if (options.shuffle) {
480 int i;
481
482 srandom(time(NULL));
483
484 for (i = 0; i < items; i++) {
485 int j = i + random() % (items - i);
486 char *temp = playlist_array[i];
487 playlist_array[i] = playlist_array[j];
488 playlist_array[j] = temp;
489 }
490 }
491
492 /* Play the files/streams */
493 i = 0;
494 while (i < items && !sig_request.exit) {
495 play(playlist_array[i]);
496 i++;
497 }
498 } while (options.repeat);
499
500 }
501 playlist_array_destroy(playlist_array, items);
502 status_deinit();
503
504 if (audio_buffer != NULL) {
505 buffer_destroy (audio_buffer);
506 audio_buffer = NULL;
507 }
508
509 ao_onexit (options.devices);
510
511 exit (exit_status);
512 }
513
play(const char * source_string)514 void play (const char *source_string)
515 {
516 const transport_t *transport;
517 format_t *format;
518 data_source_t *source;
519 decoder_t *decoder;
520
521 decoder_callbacks_t decoder_callbacks;
522 void *decoder_callbacks_arg;
523
524 /* Preserve between calls so we only open the audio device when we
525 have to */
526 static audio_format_t old_audio_fmt = { 0, 0, 0, 0, 0 };
527 audio_format_t new_audio_fmt;
528 audio_reopen_arg_t *reopen_arg;
529
530 /* Flags and counters galore */
531 int eof = 0, eos = 0, ret;
532 int nthc = 0, ntimesc = 0;
533 int next_status = 0;
534 static int status_interval = 0;
535
536 /* Reset all of the signal flags */
537 sig_request.cancel = 0;
538 sig_request.skipfile = 0;
539 sig_request.exit = 0;
540 sig_request.pause = 0;
541
542 /* Set preferred audio format (used by decoder) */
543 new_audio_fmt.big_endian = ao_is_big_endian();
544 new_audio_fmt.signed_sample = 1;
545 new_audio_fmt.word_size = 2;
546
547 /* Select appropriate callbacks */
548 if (audio_buffer != NULL) {
549 decoder_callbacks.printf_error = &decoder_buffered_error_callback;
550 decoder_callbacks.printf_metadata = &decoder_buffered_metadata_callback;
551 decoder_callbacks_arg = audio_buffer;
552 } else {
553 decoder_callbacks.printf_error = &decoder_error_callback;
554 decoder_callbacks.printf_metadata = &decoder_metadata_callback;
555 decoder_callbacks_arg = NULL;
556 }
557
558 /* Locate and use transport for this data source */
559 if ( (transport = select_transport(source_string)) == NULL ) {
560 status_error(_("No module could be found to read from %s.\n"), source_string);
561 return;
562 }
563
564 if ( (source = transport->open(source_string, &options)) == NULL ) {
565 status_error(_("Cannot open %s.\n"), source_string);
566 return;
567 }
568
569 /* Detect the file format and initialize a decoder */
570 if ( (format = select_format(source)) == NULL ) {
571 status_error(_("The file format of %s is not supported.\n"), source_string);
572 return;
573 }
574
575 if ( (decoder = format->init(source, &options, &new_audio_fmt,
576 &decoder_callbacks,
577 decoder_callbacks_arg)) == NULL ) {
578
579 /* We may have failed because of user command */
580 if (!sig_request.cancel)
581 status_error(_("Error opening %s using the %s module."
582 " The file may be corrupted.\n"), source_string,
583 format->name);
584 return;
585 }
586
587 /* Decide which statistics are valid */
588 select_stats(stat_format, &options, source, decoder, audio_buffer);
589
590 /* Start the audio playback thread before we begin sending data */
591 if (audio_buffer != NULL) {
592
593 /* First reset mutexes and other synchronization variables */
594 buffer_reset (audio_buffer);
595 buffer_thread_start (audio_buffer);
596 }
597
598 /* Show which file we are playing */
599 decoder_callbacks.printf_metadata(decoder_callbacks_arg, 1,
600 _("Playing: %s"), source_string);
601
602 /* Skip over audio */
603 if (options.seekoff > 0.0) {
604 /* Note: it may be simpler to handle this condition by just calling:
605 * handle_seek_opt(&options, decoder, format);
606 * which was introduced with the remote control interface. However, that
607 * function does not call buffer_thread_kill() on error, which is
608 * necessary in this situation.
609 */
610 if (!format->seek(decoder, options.seekoff, DECODER_SEEK_START)) {
611 status_error(_("Could not skip %f seconds of audio."), options.seekoff);
612 if (audio_buffer != NULL)
613 buffer_thread_kill(audio_buffer);
614 return;
615 }
616 }
617
618 /* Main loop: Iterates over all of the logical bitstreams in the file */
619 while (!eof && !sig_request.exit) {
620
621 /* Loop through data within a logical bitstream */
622 eos = 0;
623 while (!eos && !sig_request.exit) {
624
625 /* Check signals */
626 if (sig_request.skipfile) {
627 eof = eos = 1;
628 break;
629 }
630
631 if (options.remote) {
632
633 /* run the playloop for the remote interface */
634 if (remote_playloop()) {
635 /* end song requested */
636 eof = eos = 1;
637 break;
638 }
639
640 /* Skip over audio */
641 handle_seek_opt(&options, decoder, format);
642 }
643
644 if (sig_request.pause) {
645 if (audio_buffer)
646 buffer_thread_pause (audio_buffer);
647
648 kill (getpid(), SIGSTOP); /* We block here until we unpause */
649
650 /* Done pausing */
651 if (audio_buffer)
652 buffer_thread_unpause (audio_buffer);
653
654 sig_request.pause = 0;
655 }
656
657
658 /* Read another block of audio data */
659 ret = format->read(decoder, convbuffer, convsize, &eos, &new_audio_fmt);
660
661 /* Bail if we need to */
662 if (ret == 0) {
663 eof = eos = 1;
664 break;
665 } else if (ret < 0) {
666 status_error(_("ERROR: Decoding failure.\n"));
667 break;
668 }
669
670 /* Check to see if the audio format has changed */
671 if (!audio_format_equal(&new_audio_fmt, &old_audio_fmt)) {
672 old_audio_fmt = new_audio_fmt;
673
674 /* Update our status printing interval */
675 status_interval = new_audio_fmt.word_size * new_audio_fmt.channels *
676 new_audio_fmt.rate / options.status_freq;
677 next_status = 0;
678
679 reopen_arg = new_audio_reopen_arg(options.devices, &new_audio_fmt);
680
681 if (audio_buffer)
682 buffer_insert_action_at_end(audio_buffer, &audio_reopen_action,
683 reopen_arg);
684 else
685 audio_reopen_action(NULL, reopen_arg);
686 }
687
688
689 /* Update statistics display if needed */
690 if (next_status <= 0) {
691 display_statistics(stat_format, audio_buffer, source, decoder);
692 next_status = status_interval;
693 } else
694 next_status -= ret;
695
696 if (options.endpos > 0.0 && options.endpos <= current_time(decoder)) {
697 eof = eos = 1;
698 break;
699 }
700
701
702 /* Write audio data block to output, skipping or repeating chunks
703 as needed */
704 do {
705
706 if (nthc-- == 0) {
707 if (audio_buffer) {
708 if (!buffer_submit_data(audio_buffer, convbuffer, ret)) {
709 status_error(_("ERROR: buffer write failed.\n"));
710 eof = eos = 1;
711 break;
712 }
713 } else
714 audio_play_callback(convbuffer, ret, eos, &audio_play_arg);
715
716 nthc = options.nth - 1;
717 }
718
719 } while (!sig_request.exit && !sig_request.skipfile &&
720 ++ntimesc < options.ntimes);
721
722 ntimesc = 0;
723
724 } /* End of data loop */
725
726 } /* End of logical bitstream loop */
727
728 /* Done playing this logical bitstream. Clean up house. */
729
730 if (audio_buffer) {
731
732 if (!sig_request.exit && !sig_request.skipfile) {
733 buffer_mark_eos(audio_buffer);
734 buffer_wait_for_empty(audio_buffer);
735 }
736
737 buffer_thread_kill(audio_buffer);
738 }
739
740 /* Print final stats */
741 display_statistics_quick(stat_format, audio_buffer, source, decoder);
742
743 format->cleanup(decoder);
744 transport->close(source);
745 status_reset_output_lock(); /* In case we were killed mid-output */
746
747 status_message(1, _("Done."));
748
749 if (sig_request.exit)
750 exit (exit_status);
751 }
752
753