Ejemplo n.º 1
0
static ao_device *
audio_open_device(shairplay_options_t *opt, int bits, int channels, int samplerate)
{
	ao_device *device = NULL;
	ao_option *ao_options = NULL;
	ao_sample_format format;
	int driver_id;

	/* Get the libao driver ID */
	if (strlen(opt->ao_driver)) {
		driver_id = ao_driver_id(opt->ao_driver);
	} else {
		driver_id = ao_default_driver_id();
	}

	/* Add all available libao options */
	if (strlen(opt->ao_devicename)) {
		ao_append_option(&ao_options, "dev", opt->ao_devicename);
	}
	if (strlen(opt->ao_deviceid)) {
		ao_append_option(&ao_options, "id", opt->ao_deviceid);
	}

	/* Set audio format */
	memset(&format, 0, sizeof(format));
	format.bits = bits;
	format.channels = channels;
	format.rate = samplerate;
	format.byte_format = AO_FMT_NATIVE;

	/* Try opening the actual device */
	device = ao_open_live(driver_id, &format, ao_options);
	ao_free_options(ao_options);
	return device;
}
Ejemplo n.º 2
0
void init_ao( session_t *sess ) 
{
	if( ao_thread != 0 )
		return;

    ao_initialize();

	output_buffer_size = 4 * (sess->frame_size+3);
	output_buffer = malloc(output_buffer_size);

    int driver;
    if (libao_driver) {
        // if a libao driver is specified on the command line, use that
        driver = ao_driver_id(libao_driver);
        if (driver == -1) {
			debugp( DEBUGP_DEFAULT, 0, "Could not find requested ao driver" );
			kill( getpid(), SIGINT );
        }
    } else {
        // otherwise choose the default
        driver = ao_default_driver_id();
    }

    ao_sample_format fmt;
    memset(&fmt, 0, sizeof(fmt));
	
    fmt.bits = 16;
    fmt.rate = sess->sample_rate;
    fmt.channels = NUM_CHANNELS;
    fmt.byte_format = AO_FMT_NATIVE;
	
    ao_option *ao_opts = NULL;
    if(libao_deviceid) {
        ao_append_option(&ao_opts, "id", libao_deviceid);
    } else if(libao_devicename){
        ao_append_option(&ao_opts, "dev", libao_devicename);
        // Old libao versions (for example, 0.8.8) only support
        // "dsp" instead of "dev".
        ao_append_option(&ao_opts, "dsp", libao_devicename);
    }

    dev = ao_open_live(driver, &fmt, ao_opts);

    if (dev == NULL) {
		debugp( DEBUGP_DEFAULT, 0, "Could not open ao device (%d)", errno);
		kill( getpid(), SIGINT );
    }

	if(pthread_create( &ao_thread, NULL, ao_thread_func, NULL ))
	{
		debugp( DEBUGP_DEFAULT, 0, "Could not start ao_thread\n" );
		kill( getpid(), SIGINT );
	}

    return;
}
Ejemplo n.º 3
0
int fm_player_open(fm_player_t *pl, fm_player_config_t *config)
{
    pl->config = *config;

    if (strcmp(config->driver, "pifm") == 0)
    {
        float f = atof(config->dev);
        if (f < 1)
            f = 102.4;
        printf("Player audio driver: pifm\n");
        printf("Player sample rate: %d Hz\n", config->rate);
        printf("Player FM fequency: %f Hz\n", f);
        config->channels = 1;
        fm_setup_fm();
        fm_setup_dma(f);
    }
    else
    {
        ao_sample_format ao_fmt;
        ao_fmt.rate = config->rate;
        ao_fmt.channels = config->channels;
        ao_fmt.bits = mpg123_encsize(config->encoding) * 8;
        ao_fmt.byte_format = AO_FMT_NATIVE;
        ao_fmt.matrix = 0;
        
        int driver = ao_driver_id(config->driver);
        if (driver == -1) {
            return -1;
        }
        
        ao_info *driver_info = ao_driver_info(driver);
        printf("Player audio driver: %s\n", driver_info->name);
        printf("Player sample rate: %d Hz\n", pl->config.rate);
        ao_option *options = NULL;
        if (config->dev[0] != '\0') {
            ao_append_option(&options, "dev", config->dev);
        }
        pl->dev = ao_open_live(driver, &ao_fmt, options);
        ao_free_options(options);
        if (pl->dev == NULL)
            return -1;
    }

    pl->mh = mpg123_new(NULL, NULL);
    mpg123_format_none(pl->mh);
    mpg123_format(pl->mh, config->rate, config->channels, config->encoding);

    pl->curl = curl_easy_init();
    curl_easy_setopt(pl->curl, CURLOPT_WRITEFUNCTION, download_callback);
    curl_easy_setopt(pl->curl, CURLOPT_WRITEDATA, pl);

    pl->tid_ack = 0;

    pthread_mutex_init(&pl->mutex_status, NULL);
    pthread_cond_init(&pl->cond_play, NULL);

    pl->status = FM_PLAYER_STOP;

    return 0;
}
Ejemplo n.º 4
0
static ao_option *
dict_to_options(PyObject *dict)
{
  Py_ssize_t pos = 0;
  PyObject *key, *val;
  ao_option *head = NULL;
  int ret;
  

  if (!PyDict_Check(dict)) {
    PyErr_SetString(PyExc_TypeError, "Must be a dictionary");
    return NULL;
  }
  
  while (PyDict_Next(dict, &pos, &key, &val) > 0) {
    if (!PyString_Check(key) || !PyString_Check(val)) {
      PyErr_SetString(PyExc_TypeError, "Option keys may only be strings");
      goto error;
    }

    ret = ao_append_option(&head, PyString_AsString(key), PyString_AsString(val));
    if (ret == 0) {
      PyErr_SetString(Py_aoError, "Error appending options");
      goto error;
    }
  }
  return head;

 error:
  ao_free_options(head);
  return NULL;
}
Ejemplo n.º 5
0
static int
parse_driver_options( const char *device, int *driver_id, ao_option **options )
{
  char *mutable, *option, *key, *value;

  /* Get a copy of the device string we can modify */
  if( !device || *device == '\0' )
    return 0;

  mutable = strdup( device );
  if( !mutable ) {
    ui_error( UI_ERROR_ERROR, "out of memory at %s:%d", __FILE__, __LINE__ );
    return 1;
  }

  /* First, find the device name */
  option = strchr( mutable, ':' );
  if( option ) *option++ = '\0';

  if( *mutable )				/* ! \0 */
    *driver_id = ao_driver_id( mutable );

  /* Now parse any further options */
  while( option ) {

    key = option;

    option = strchr( option, ',' );
    if( option ) *option++ = '\0';

    value = strchr( key, '=' );
    if( value ) *value++ = '\0';

    if( strcmp( key, "file" ) == 0 ) {
      filename = strdup( value );
      if( !filename ) {
	ui_error( UI_ERROR_ERROR, "out of memory at %s:%d", __FILE__,
		  __LINE__ );
	free( mutable );
	return 1;
      }
    } else if( key && value) {
      ao_append_option( options, key, value );
    } else if ( first_init ) {
	ui_error( UI_ERROR_ERROR, "ignoring badly formed libao option (%s%s)",
		key ? key : "", value ? value : "" );
    }

  }

  free( mutable );

  return 0;
}
Ejemplo n.º 6
0
void process_config_options(const struct uade_config *uc)
{
  char *s;
  char *key;
  char *value;

  if (uc->buffer_time > 0) {
      char val[32];
      /* buffer_time is given in milliseconds, so convert to microseconds */
      snprintf(val, sizeof val, "%d", 1000 * uc->buffer_time);
      ao_append_option(&options, "buffer_time", val);
  }

  format.bits = UADE_BYTES_PER_SAMPLE * 8;
  format.channels = UADE_CHANNELS;
  format.rate = uc->frequency;
  format.byte_format = AO_FMT_NATIVE;

  s = (char *) uc->ao_options.o;
  while (s != NULL && *s != 0) {
    key = s;

    s = strchr(s, '\n');
    if (s == NULL)
      break;
    *s = 0;
    s++;

    value = strchr(key, ':');
    if (value == NULL) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "uade: Invalid ao option: %s\n", key);
      continue;
    }
    *value = 0;
    value++;

    ao_append_option(&options, key, value);
  }
}
Ejemplo n.º 7
0
static void add_driver_option(const char *key_value) {
    char buf[1024];
    char *value = NULL;
    char *sep;

    strncpy(buf, key_value, sizeof(buf));
    buf[sizeof(buf) - 1] = '\0';

    sep = strchr(buf, ':');
    if (sep) {
        *sep = '\0';
        value = sep + 1;
    }

    ao_append_option(&device_options, buf, value);
}
Ejemplo n.º 8
0
int add_ao_option(ao_option **op_h, const char *optstring)
{
  char *key, *value;
  int result;

  key = strdup(optstring);
  if (key == NULL)
    return 0;

  value = strchr(key, ':');
  if (value) {
    /* split by replacing the separator with a null */
    *value++ = '\0';
  }

  result = ao_append_option(op_h, key, value);
  free(key);

  return (result);
}
Ejemplo n.º 9
0
static struct audio_output *
ao_output_init(const struct config_param *param,
	       GError **error)
{
	struct ao_data *ad = g_new(struct ao_data, 1);

	if (!ao_base_init(&ad->base, &ao_output_plugin, param, error)) {
		g_free(ad);
		return NULL;
	}

	ao_info *ai;
	const char *value;

	ad->options = NULL;

	ad->write_size = config_get_block_unsigned(param, "write_size", 1024);

	if (ao_output_ref == 0) {
		ao_initialize();
	}
	ao_output_ref++;

	value = config_get_block_string(param, "driver", "default");
	if (0 == strcmp(value, "default"))
		ad->driver = ao_default_driver_id();
	else
		ad->driver = ao_driver_id(value);

	if (ad->driver < 0) {
		g_set_error(error, ao_output_quark(), 0,
			    "\"%s\" is not a valid ao driver",
			    value);
		ao_base_finish(&ad->base);
		g_free(ad);
		return NULL;
	}

	if ((ai = ao_driver_info(ad->driver)) == NULL) {
		g_set_error(error, ao_output_quark(), 0,
			    "problems getting driver info");
		ao_base_finish(&ad->base);
		g_free(ad);
		return NULL;
	}

	g_debug("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
		config_get_block_string(param, "name", NULL));

	value = config_get_block_string(param, "options", NULL);
	if (value != NULL) {
		gchar **options = g_strsplit(value, ";", 0);

		for (unsigned i = 0; options[i] != NULL; ++i) {
			gchar **key_value = g_strsplit(options[i], "=", 2);

			if (key_value[0] == NULL || key_value[1] == NULL) {
				g_set_error(error, ao_output_quark(), 0,
					    "problems parsing options \"%s\"",
					    options[i]);
				ao_base_finish(&ad->base);
				g_free(ad);
				return NULL;
			}

			ao_append_option(&ad->options, key_value[0],
					 key_value[1]);

			g_strfreev(key_value);
		}

		g_strfreev(options);
	}

	return &ad->base;
}
Ejemplo n.º 10
0
ao_device *open_ao_playdevice_buffer(struct mad_header const *header)
{
        ao_sample_format format;
	ao_device *pldev = NULL;

        /* Because these can sometimes block, we stop our custom signal handler,
           and restore it afterwards */
        signal(SIGINT, SIG_DFL);
        
        format.bits = 16;
        format.rate = header->samplerate;
        format.channels = (options.opt & MPG321_FORCE_STEREO) ? 2 : MAD_NCHANNELS(header);
	
	/* Add this element as an option to mpg321 */
	format.matrix = "L,R";

        /* mad gives us little-endian data; we swap it on big-endian targets, to
          big-endian format, because that's what most drivers expect. */
        format.byte_format = AO_FMT_NATIVE; 
        
        if(options.opt & MPG321_USE_AU)
        {
            int driver_id = ao_driver_id("au");
            ao_option *ao_options = NULL;

            /* Don't have to check options.device here: we only define
               MPG321_USE_AU when --au <aufile> is defined, and <aufile>
               is pointd to by options.device */
            if((pldev=ao_open_file(driver_id, options.device, 1 /*overwrite*/,
                    &format, ao_options))==NULL)
            {
                fprintf(stderr, "Error opening libao file output driver to write AU data.\n");
                return NULL;
            }
        }

        else if (options.opt & MPG321_USE_CDR)
        {
            ao_option * ao_options = NULL;
            int driver_id = ao_driver_id("raw");

            /* because CDR is a special format, i.e. headerless PCM, big endian,
               this is a special case. */
            ao_append_option(&ao_options, "byteorder", "big");
        
            if((pldev=ao_open_file(driver_id, options.device, 1 /*overwrite*/, 
                    &format, ao_options))==NULL)
            {
                fprintf(stderr, "Error opening libao file output driver to write CDR data.\n");
                return NULL;
            }
        }
        
        /* if the user specifies both au and wave, wav will be prefered, so testing
         * later */
        else if(options.opt & MPG321_USE_WAV)
        {
            int driver_id = ao_driver_id("wav");
            ao_option *ao_options = NULL;

            /* Don't have to check options.device here: we only define
               MPG321_USE_WAV when -w <wavfile> is defined, and <wavfile>
               is pointd to by options.device */
            if((pldev=ao_open_file(driver_id, options.device, 1 /*overwrite*/,
                    &format, ao_options))==NULL)
            {
                fprintf(stderr, "Error opening libao wav file driver. (Do you have write permissions?)\n");
                return NULL;
            }
        }

        else if(options.opt & MPG321_USE_NULL)
        {
            int driver_id = ao_driver_id("null"); 
            /* null is dirty, create a proper options struct later */

            if((pldev = ao_open_live(driver_id, &format, NULL)) == NULL)
            {
                fprintf(stderr, "Error opening libao null driver. (This shouldn't have happened.)\n");
                return NULL;
            }
        }
        
        else if (options.opt & MPG321_USE_STDOUT)
        {
            ao_option * ao_options = NULL;
            int driver_id = ao_driver_id("raw");

            /* stdout output is expected to be little-endian generally */
            ao_append_option(&ao_options, "byteorder", "little");
        
            if((pldev=ao_open_file(driver_id, "-", 1 /*overwrite*/, 
                    &format, ao_options))==NULL)
            {
                fprintf(stderr, "Error opening libao raw output driver.\n");
                return NULL;
            }
        }
        
        else if (options.opt & MPG321_USE_USERDEF)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id(options.devicetype);
            
	    if (driver_id < 0)
            {
                fprintf(stderr, "Can't open unknown ao driver %s\n", options.devicetype);
                exit(1);
            }

            if (playdevice_is_live())
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't set output device to %s for unknown ao plugin %s",
                            options.device, options.devicetype);
                }

                if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
                {
                    fprintf(stderr, "Error opening unknown libao %s driver. (Is device in use?)\n",
                        options.devicetype);
                    return NULL;
                }
            }

            else
            {
                if (options.device)
                {
                    /* Just assume that options.device is a filename. The user can shoot 
                       themselves in the foot all they like... */
                    if((pldev=ao_open_file(driver_id, options.device, 1 /*overwrite*/,
                            &format, ao_options))==NULL)
                    {
                        fprintf(stderr, "Error opening unknown libao %s file driver for file %s. (Do you have write permissions?)\n",
                                options.devicetype, options.device);
                        return NULL;
                    }
                }
                
                else
                {
                    fprintf(stderr, "Filename must be specified (with -a filename) for unknown ao driver %s\n",
                            options.devicetype);
                }
            }
        } else {
            /* Hack-tacular. This code tries to the device as specified; if it can't, it'll
               fall through to the other devices, trying each in turn. If the user specified
               a device to use, though, it won't fall through: principle of least surprise */
        int opened = 0;

        if(!opened && options.opt & MPG321_USE_ALSA)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("alsa");
            char *c;
            char *card=(char *)malloc((int)16);
            memset(card,0,16); 
	    strncat(card,"alsa:\0",6);
	    
	    if (options.device)
            {
	    	strcat(card,options.device);
                //if ((c = strchr(options.device, ':')) == NULL || strlen(c+1) < 1)
                if ((c = strchr(card, ':')) == NULL || strlen(c+1) < 1)
                {
                    fprintf(stderr, "Poorly formed ALSA card:device specification %s", options.device);
                    exit(1);
                }

                *(c++) = '\0'; /* change the : to a null to create two separate strings */
                //ao_append_option(&ao_options, "card", options.device);
                ao_append_option(&ao_options, "card", card);
                ao_append_option(&ao_options, "dev", c);
            }

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_ALSA09;
            } else opened++;
        }

        if(!opened && options.opt & MPG321_USE_ALSA09)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("alsa09");

            if(options.device)
                ao_append_option(&ao_options, "dev", options.device);

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_OSS;
            } else opened++;
        }

        if(!opened &&  options.opt & MPG321_USE_OSS)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("oss");

            if(options.device)
                ao_append_option(&ao_options, "dsp", options.device);

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_SUN;
            } else opened++;
        }

        if(!opened && options.opt & MPG321_USE_SUN)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("sun");

            if(options.device)
                ao_append_option(&ao_options, "dev", options.device);

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_ESD;
            }
        }

        if(!opened && options.opt & MPG321_USE_ESD)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("esd");

            if(options.device)
                ao_append_option(&ao_options, "host", options.device);

            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                if (options.device)
                {
                    fprintf(stderr, "Can't open libao driver with device %s (is device in use?)\n",
                        options.device);
                    return NULL;
                }
                else
                options.opt |= MPG321_USE_ARTS;
            } else opened++;
        }

        if(!opened && options.opt & MPG321_USE_ARTS)
        {
            ao_option *ao_options = NULL;
            int driver_id = ao_driver_id("arts");
        
            if((pldev=ao_open_live(driver_id, &format, ao_options))==NULL)
            {
                fprintf(stderr, "Can't find a suitable libao driver. (Is device in use?)\n");
                return NULL;
            }
        }
        
    }

    /* Restore signal handler */
    signal(SIGINT, handle_signals);
    return pldev;
}
Ejemplo n.º 11
0
static int init(int argc, char **argv) {
  const char *str;
  int value;
  ao_initialize();
  int driver = ao_default_driver_id();
  ao_option *ao_opts = NULL;

  config.audio_backend_buffer_desired_length = 44100; // one second.
  config.audio_backend_latency_offset = 0;
  
  // get settings from settings file first, allow them to be overridden by command line options

  if (config.cfg != NULL) {
    /* Get the desired buffer size setting. */
    if (config_lookup_int(config.cfg, "ao.audio_backend_buffer_desired_length", &value)) {
      if ((value < 0) || (value > 66150))
        die("Invalid a0 audio backend buffer desired length \"%d\". It should be between 0 and "
            "66150, default is 44100",
            value);
      else {
        config.audio_backend_buffer_desired_length = value;
      }
    }
    
    /* Get the latency offset. */
    if (config_lookup_int(config.cfg, "ao.audio_backend_latency_offset", &value)) {
      if ((value < -66150) || (value > 66150))
        die("Invalid ao audio backend buffer latency offset \"%d\". It should be between -66150 and +66150, default is 0",
            value);
      else
        config.audio_backend_latency_offset = value;
    }
  }


  optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour
  argv--;     // so we shift the arguments to satisfy getopt()
  argc++;

  // some platforms apparently require optreset = 1; - which?
  int opt;
  char *mid;
  while ((opt = getopt(argc, argv, "d:i:n:o:")) > 0) {
    switch (opt) {
    case 'd':
      driver = ao_driver_id(optarg);
      if (driver < 0)
        die("could not find ao driver %s", optarg);
      break;
    case 'i':
      ao_append_option(&ao_opts, "id", optarg);
      break;
    case 'n':
      ao_append_option(&ao_opts, "dev", optarg);
      // Old libao versions (for example, 0.8.8) only support
      // "dsp" instead of "dev".
      ao_append_option(&ao_opts, "dsp", optarg);
      break;
    case 'o':
      mid = strchr(optarg, '=');
      if (!mid)
        die("Expected an = in audio option %s", optarg);
      *mid = 0;
      ao_append_option(&ao_opts, optarg, mid + 1);
      break;
    default:
      help();
      die("Invalid audio option -%c specified", opt);
    }
  }

  if (optind < argc)
    die("Invalid audio argument: %s", argv[optind]);

  ao_sample_format fmt;
  memset(&fmt, 0, sizeof(fmt));

  fmt.bits = 16;
  fmt.rate = 44100;
  fmt.channels = 2;
  fmt.byte_format = AO_FMT_NATIVE;

  dev = ao_open_live(driver, &fmt, ao_opts);

  return dev ? 0 : 1;
}
Ejemplo n.º 12
0
int ao_append_global_option(const char *key, const char *value)
{
  return ao_append_option(&ao_global_options,key,value);
}
Ejemplo n.º 13
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;

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

      switch (ret) {
      case 0:
	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;
      case 'b':
	ogg123_opts->input_buffer_size = atoi(optarg) * 1024;
	if (ogg123_opts->input_buffer_size < MIN_INPUT_BUFFER_SIZE * 1024) {
	  status_error(_("Input buffer size smaller than minimum size of %dkB."),
		       MIN_INPUT_BUFFER_SIZE);
	  ogg123_opts->input_buffer_size = MIN_INPUT_BUFFER_SIZE * 1024;
	}
	break;
	
      case 'c':
	if (optarg) {
	  char *tmp = strdup (optarg);
	  parse_code_t pcode = parse_line(file_opts, tmp);

	  if (pcode != parse_ok)
	    status_error(_("=== Error \"%s\" while parsing config option from command line.\n"
			 "=== Option was: %s\n"),
			 parse_error_string(pcode), optarg);
	  free (tmp);
	}
	else {
	  /* not using the status interface here */
	  fprintf (stdout, _("Available options:\n"));
	  file_options_describe(file_opts, stdout);
	  exit (0);
	}
	break;
	
      case 'd':
	temp_driver_id = ao_driver_id(optarg);
	if (temp_driver_id < 0) {
	    status_error(_("=== No such device %s.\n"), optarg);
	    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 {
	    status_error(_("=== Driver %s is not a file output driver.\n"),
			 info->short_name);
	    exit(1);
	  }
	} else {
	  status_error(_("=== Cannot specify output file without specifying a driver.\n"));
	  exit (1);
	}
	break;

	case 'k':
 	  set_seek_opt(ogg123_opts, optarg);
	  break;
	  
	case 'K':
	  ogg123_opts->endpos = strtotime(optarg);
	  break;
	  
	case 'l':
	  ogg123_opts->delay = atoi(optarg);
	  break;
	  
	case 'o':
	  if (optarg && !add_ao_option(current_options, optarg)) {
	    status_error(_("=== Incorrect option format: %s.\n"), optarg);
	    exit(1);
	  }
	  break;

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

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

	    status_error (_("--- Prebuffer value invalid. Range is 0-100.\n"));
	    ogg123_opts->input_prebuffer = 
	      ogg123_opts->input_prebuffer < 0.0f ? 0.0f : 100.0f;
	  }
	  break;

      case 'q':
	ogg123_opts->verbosity = 0;
	break;
	
      case 'r':
        ogg123_opts->repeat = 1;
	break;

      case 'R':
	ogg123_opts->remote = 1;
	ogg123_opts->verbosity = 0;
	break;

      case 'v':
	ogg123_opts->verbosity++;
	break;
	
      case 'V':
	status_error(_("ogg123 from %s %s"), PACKAGE, VERSION);
	exit(0);
	break;

      case 'x':
	ogg123_opts->nth = atoi(optarg);
	if (ogg123_opts->nth == 0) {
	  status_error(_("--- Cannot play every 0th chunk!\n"));
	  ogg123_opts->nth = 1;
	}
	break;
	  
      case 'y':
	ogg123_opts->ntimes = atoi(optarg);
	if (ogg123_opts->ntimes == 0) {
	  status_error(_("--- Cannot play every chunk 0 times.\n"
		 "--- To do a test decode, use the null output driver.\n"));
	  ogg123_opts->ntimes = 1;
	}
	break;
	
      case 'z':
	ogg123_opts->shuffle = 1;
	break;

      case 'Z':
        ogg123_opts->repeat = ogg123_opts->shuffle = 1;
	break;

      case '@':
	if (playlist_append_from_file(ogg123_opts->playlist, optarg) == 0)
	  status_error(_("--- Cannot open playlist file %s.  Skipped.\n"),
		       optarg);
	break;
		
      case '?':
	break;
	
      default:
	cmdline_usage();
	exit(1);
      }
  }

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


  /* 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)
	    status_error(_("--- Driver %s specified in configuration file invalid.\n"),
			 ogg123_opts->default_device);
      }

      /* Then try libao autodetect */
      if (temp_driver_id < 0)
	temp_driver_id = ao_default_driver_id();

      /* Finally, give up */
      if (temp_driver_id < 0) {
	status_error(_("=== Could not load default driver and no driver specified in config file. Exiting.\n"));
	exit(1);
      }

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

  /* if verbosity has been altered, add options to drivers... */
  {
    audio_device_t *head = ogg123_opts->devices;
    while (head){
      if(ogg123_opts->verbosity>3)
        ao_append_global_option("debug",NULL);
      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;
    }
  }


  return optind;
}