cmdline_options.c 11.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/********************************************************************
 *                                                                  *
 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE.    *
 * PLEASE READ THESE TERMS BEFORE DISTRIBUTING.                     *
 *                                                                  *
 * THE Ogg123 SOURCE CODE IS (C) COPYRIGHT 2000-2001                *
 * by Stan Seibert <volsung@xiph.org> AND OTHER CONTRIBUTORS        *
 * http://www.xiph.org/                                             *
 *                                                                  *
 ********************************************************************

Monty's avatar
Monty committed
14
 last mod: $Id$
15 16 17

 ********************************************************************/

18 19 20
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
21 22 23
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
24
#include <vorbis/vorbisfile.h>
25 26 27 28 29
#include <ao/ao.h>

#include "getopt.h"
#include "cmdline_options.h"
#include "status.h"
30
#include "i18n.h"
31

32 33
#define MIN_INPUT_BUFFER_SIZE 8

34 35 36
extern double strtotime(char *s);
extern void set_seek_opt(ogg123_options_t *ogg123_opts, char *buf);

37 38 39 40 41 42 43 44 45 46
struct option long_options[] = {
  /* GNU standard options */
    {"help", no_argument, 0, 'h'},
    {"version", no_argument, 0, 'V'},
    /* ogg123-specific options */
    {"buffer", required_argument, 0, 'b'},
    {"config", optional_argument, 0, 'c'},
    {"device", required_argument, 0, 'd'},
    {"file", required_argument, 0, 'f'},
    {"skip", required_argument, 0, 'k'},
47
    {"end", required_argument, 0, 'K'},
48 49 50 51
    {"delay", required_argument, 0, 'l'},
    {"device-option", required_argument, 0, 'o'},
    {"prebuffer", required_argument, 0, 'p'},
    {"quiet", no_argument, 0, 'q'},
52
    {"remote", no_argument, 0, 'R'},
53 54 55 56
    {"verbose", no_argument, 0, 'v'},
    {"nth", required_argument, 0, 'x'},
    {"ntimes", required_argument, 0, 'y'},
    {"shuffle", no_argument, 0, 'z'},
57
    {"random", no_argument, 0, 'Z'},
58
    {"list", required_argument, 0, '@'},
59
    {"audio-buffer", required_argument, 0, 0},
Conrad Parker's avatar
Conrad Parker committed
60
    {"repeat", no_argument, 0, 'r'},
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
    {0, 0, 0, 0}
};

int parse_cmdline_options (int argc, char **argv,
			   ogg123_options_t *ogg123_opts,
			   file_option_t    *file_opts)
{
  int option_index = 1;
  ao_option *temp_options = NULL;
  ao_option ** current_options = &temp_options;
  ao_info *info;
  int temp_driver_id = -1;
  audio_device_t *current;
  int ret;

76
  while (-1 != (ret = getopt_long(argc, argv, "b:c::d:f:hl:k:K:o:p:qrRvVx:y:zZ@:",
77 78 79 80
				  long_options, &option_index))) {

      switch (ret) {
      case 0:
81 82 83 84 85 86 87
	if(!strcmp(long_options[option_index].name, "audio-buffer")) {
	  ogg123_opts->buffer_size = 1024 * atoi(optarg);
	} else {
	  status_error(_("Internal error parsing command line options.\n"));
	  exit(1);
	}
	break;
88
      case 'b':
89 90
	ogg123_opts->input_buffer_size = atoi(optarg) * 1024;
	if (ogg123_opts->input_buffer_size < MIN_INPUT_BUFFER_SIZE * 1024) {
91
	  status_error(_("Input buffer size smaller than minimum size of %dkB."),
92 93 94
		       MIN_INPUT_BUFFER_SIZE);
	  ogg123_opts->input_buffer_size = MIN_INPUT_BUFFER_SIZE * 1024;
	}
95 96 97 98 99 100 101 102
	break;
	
      case 'c':
	if (optarg) {
	  char *tmp = strdup (optarg);
	  parse_code_t pcode = parse_line(file_opts, tmp);

	  if (pcode != parse_ok)
103 104
	    status_error(_("=== Error \"%s\" while parsing config option from command line.\n"
			 "=== Option was: %s\n"),
105 106 107 108 109
			 parse_error_string(pcode), optarg);
	  free (tmp);
	}
	else {
	  /* not using the status interface here */
110
	  fprintf (stdout, _("Available options:\n"));
111 112 113 114 115 116 117 118
	  file_options_describe(file_opts, stdout);
	  exit (0);
	}
	break;
	
      case 'd':
	temp_driver_id = ao_driver_id(optarg);
	if (temp_driver_id < 0) {
119
	    status_error(_("=== No such device %s.\n"), optarg);
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
	    exit(1);
	}

	current = append_audio_device(ogg123_opts->devices,
				      temp_driver_id, 
				      NULL, NULL);
	if(ogg123_opts->devices == NULL)
	  ogg123_opts->devices = current;
	current_options = &current->options;
	break;
	
      case 'f':
	if (temp_driver_id >= 0) {

	  info = ao_driver_info(temp_driver_id);
	  if (info->type == AO_TYPE_FILE) {
	    free(current->filename);
	    current->filename = strdup(optarg);
	  } else {
139
	    status_error(_("=== Driver %s is not a file output driver.\n"),
140 141 142 143
			 info->short_name);
	    exit(1);
	  }
	} else {
144
	  status_error(_("=== Cannot specify output file without previously specifying a driver.\n"));
145 146 147 148 149
	  exit (1);
	}
	break;

	case 'k':
150
 	  set_seek_opt(ogg123_opts, optarg);
151 152 153 154
	  break;
	  
	case 'K':
	  ogg123_opts->endpos = strtotime(optarg);
155 156 157
	  break;
	  
	case 'l':
158
	  ogg123_opts->delay = atoi(optarg);
159 160 161 162
	  break;
	  
	case 'o':
	  if (optarg && !add_ao_option(current_options, optarg)) {
163
	    status_error(_("=== Incorrect option format: %s.\n"), optarg);
164 165 166 167 168 169 170 171
	    exit(1);
	  }
	  break;

	case 'h':
	  cmdline_usage();
	  exit(0);
	  break;
172

173
	case 'p':
174 175 176
	  ogg123_opts->input_prebuffer = atof (optarg);
	  if (ogg123_opts->input_prebuffer < 0.0f || 
	      ogg123_opts->input_prebuffer > 100.0f) {
177

178
	    status_error (_("--- Prebuffer value invalid. Range is 0-100.\n"));
179 180
	    ogg123_opts->input_prebuffer = 
	      ogg123_opts->input_prebuffer < 0.0f ? 0.0f : 100.0f;
181 182 183 184 185 186 187
	  }
	  break;

      case 'q':
	ogg123_opts->verbosity = 0;
	break;
	
Conrad Parker's avatar
Conrad Parker committed
188 189 190 191
      case 'r':
        ogg123_opts->repeat = 1;
	break;

192 193 194 195 196
      case 'R':
	ogg123_opts->remote = 1;
	ogg123_opts->verbosity = 0;
	break;

197 198 199 200 201
      case 'v':
	ogg123_opts->verbosity++;
	break;
	
      case 'V':
202
	status_error(_("ogg123 from %s %s"), PACKAGE, VERSION);
203 204 205 206 207 208
	exit(0);
	break;

      case 'x':
	ogg123_opts->nth = atoi(optarg);
	if (ogg123_opts->nth == 0) {
209
	  status_error(_("--- Cannot play every 0th chunk!\n"));
210 211 212 213 214 215 216
	  ogg123_opts->nth = 1;
	}
	break;
	  
      case 'y':
	ogg123_opts->ntimes = atoi(optarg);
	if (ogg123_opts->ntimes == 0) {
217 218
	  status_error(_("--- Cannot play every chunk 0 times.\n"
		 "--- To do a test decode, use the null output driver.\n"));
219 220 221 222 223 224 225
	  ogg123_opts->ntimes = 1;
	}
	break;
	
      case 'z':
	ogg123_opts->shuffle = 1;
	break;
226

227 228 229 230
      case 'Z':
        ogg123_opts->repeat = ogg123_opts->shuffle = 1;
	break;

231 232 233 234 235 236
      case '@':
	if (playlist_append_from_file(ogg123_opts->playlist, optarg) == 0)
	  status_error(_("--- Cannot open playlist file %s.  Skipped.\n"),
		       optarg);
	break;
		
237 238 239 240 241 242 243 244 245
      case '?':
	break;
	
      default:
	cmdline_usage();
	exit(1);
      }
  }

246 247
  /* Sanity check bad option combinations */
  if (ogg123_opts->endpos > 0.0 &&
248
      ogg123_opts->seekoff > ogg123_opts->endpos) {
249 250 251 252 253
    status_error(_("=== Option conflict: End time is before start time.\n"));
    exit(1);
  }


254 255 256 257 258 259 260 261
  /* Add last device to device list or use the default device */
  if (temp_driver_id < 0) {

      /* First try config file setting */
      if (ogg123_opts->default_device) {
	  temp_driver_id = ao_driver_id(ogg123_opts->default_device);

	  if (temp_driver_id < 0)
262
	    status_error(_("--- Driver %s specified in configuration file invalid.\n"),
263 264
			 ogg123_opts->default_device);
      }
265

266 267 268 269 270 271
      /* Then try libao autodetect */
      if (temp_driver_id < 0)
	temp_driver_id = ao_default_driver_id();

      /* Finally, give up */
      if (temp_driver_id < 0) {
272
	status_error(_("=== Could not load default driver and no driver specified in config file. Exiting.\n"));
273 274 275 276 277 278 279 280 281
	exit(1);
      }

      ogg123_opts->devices = append_audio_device(ogg123_opts->devices,
					     temp_driver_id,
					     temp_options, 
					     NULL);
    }

282 283 284 285
  /* if verbosity has been altered, add options to drivers... */
  {
    audio_device_t *head = ogg123_opts->devices;
    while (head){
286 287
      if(ogg123_opts->verbosity>3)
        ao_append_global_option("debug",NULL);
288 289 290 291 292 293 294 295
      if(ogg123_opts->verbosity>2)
        ao_append_option(&(head->options),"verbose",NULL);
      if(ogg123_opts->verbosity==0)
        ao_append_option(&(head->options),"quiet",NULL);
      head = head->next_device;
    }
  }

296 297 298 299

  return optind;
}

Conrad Parker's avatar
Conrad Parker committed
300
#define LIST_SEP(x) ((x)==0?' ':',')
301 302 303

void cmdline_usage (void)
{
Conrad Parker's avatar
Conrad Parker committed
304
  int i, j, driver_count;
305 306
  ao_info **devices = ao_driver_info_list(&driver_count);

Conrad Parker's avatar
Conrad Parker committed
307
  printf (_("ogg123 from %s %s\n"
308 309
         " by the Xiph.Org Foundation (https://www.xiph.org/)\n"), PACKAGE, VERSION);
  printf (_(" using decoder %s.\n\n"), vorbis_version_string());
Conrad Parker's avatar
Conrad Parker committed
310

311 312
  printf (_("Usage: ogg123 [options] file ...\n"
	    "Play Ogg audio files and network streams.\n\n"));
Conrad Parker's avatar
Conrad Parker committed
313 314 315 316 317 318 319 320 321 322 323 324 325
 
  printf (_("Available codecs: "));

#ifdef HAVE_LIBFLAC
  printf (_("FLAC, "));
#endif

#ifdef HAVE_LIBSPEEX
  printf (_("Speex, "));
#endif

  printf (_("Ogg Vorbis.\n\n"));

326 327 328 329
  printf (_("Output options\n"));
  printf (_("  -d dev, --device dev    Use output device \"dev\". Available devices:\n"));
  printf ("                          ");
  printf (_("Live:"));
330

Conrad Parker's avatar
Conrad Parker committed
331 332 333 334 335
  for(i = 0, j = 0; i < driver_count; i++) {
    if (devices[i]->type == AO_TYPE_LIVE) {
      printf ("%c %s", LIST_SEP(j), devices[i]->short_name);
      j++;
    }
336
  }
337 338
  printf ("\n                          ");
  printf (_("File:"));
Conrad Parker's avatar
Conrad Parker committed
339 340 341 342 343 344 345
  for(i = 0, j = 0; i < driver_count; i++) {
    if (devices[i]->type == AO_TYPE_FILE) {
      printf ("%c %s", LIST_SEP(j), devices[i]->short_name);
      j++;
    }
  }
  printf ("\n\n");
346

347 348 349 350 351 352 353 354 355
  printf (_("  -f file, --file file    Set the output filename for a file device\n"
	    "                          previously specified with --device.\n"));
  printf ("\n");
  printf (_("  --audio-buffer n        Use an output audio buffer of 'n' kilobytes\n"));
  printf (_("  -o k:v, --device-option k:v\n"
	    "                          Pass special option 'k' with value 'v' to the\n"
	    "                          device previously specified with --device. See\n"
	    "                          the ogg123 man page for available device options.\n"));
  printf ("\n");
356

357 358 359
  printf (_("Playlist options\n"));
  printf (_("  -@ file, --list file    Read playlist of files and URLs from \"file\"\n"));
  printf (_("  -r, --repeat            Repeat playlist indefinitely\n"));
360
  printf (_("  -R, --remote            Use remote control interface\n"));
361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
  printf (_("  -z, --shuffle           Shuffle list of files before playing\n"));
  printf (_("  -Z, --random            Play files randomly until interrupted\n"));
  printf ("\n");

  printf (_("Input options\n"));
  printf (_("  -b n, --buffer n        Use an input buffer of 'n' kilobytes\n"));
  printf (_("  -p n, --prebuffer n     Load n%% of the input buffer before playing\n"));
  printf ("\n");

  printf (_("Decode options\n"));
  printf (_("  -k n, --skip n          Skip the first 'n' seconds (or hh:mm:ss format)\n"));
  printf (_("  -K n, --end n           End at 'n' seconds (or hh:mm:ss format)\n"));
  printf (_("  -x n, --nth n           Play every 'n'th block\n"));
  printf (_("  -y n, --ntimes n        Repeat every played block 'n' times\n"));
  printf ("\n");

  printf (_("Miscellaneous options\n"));
  printf (_("  -l s, --delay s         Set termination timeout in milliseconds. ogg123\n"
	    "                          will skip to the next song on SIGINT (Ctrl-C),\n"
	    "                          and will terminate if two SIGINTs are received\n"
	    "                          within the specified timeout 's'. (default 500)\n"));
  printf ("\n");
  printf (_("  -h, --help              Display this help\n"));
  printf (_("  -q, --quiet             Don't display anything (no title)\n"));
  printf (_("  -v, --verbose           Display progress and other status information\n"));
  printf (_("  -V, --version           Display ogg123 version\n"));
  printf ("\n");
Conrad Parker's avatar
Conrad Parker committed
388

389
}