// returns 1 if successful
int setSWParams(AlsaPcmInfo* info) {
    int ret;

    /* get the current swparams */
    ret = snd_pcm_sw_params_current(info->handle, info->swParams);
    if (ret < 0) {
        ERROR1("Unable to determine current swparams: %s\n", snd_strerror(ret));
        return FALSE;
    }
    /* never start the transfer automatically */
    if (!setStartThresholdNoCommit(info, FALSE /* don't use threshold */)) {
        return FALSE;
    }

    /* allow the transfer when at least period_size samples can be processed */
    ret = snd_pcm_sw_params_set_avail_min(info->handle, info->swParams, info->periodSize);
    if (ret < 0) {
        ERROR1("Unable to set avail min for playback: %s\n", snd_strerror(ret));
        return FALSE;
    }
    /* align all transfers to 1 sample */
    ret = snd_pcm_sw_params_set_xfer_align(info->handle, info->swParams, 1);
    if (ret < 0) {
        ERROR1("Unable to set transfer align: %s\n", snd_strerror(ret));
        return FALSE;
    }
    /* write the parameters to the playback device */
    ret = snd_pcm_sw_params(info->handle, info->swParams);
    if (ret < 0) {
        ERROR1("Unable to set sw params: %s\n", snd_strerror(ret));
        return FALSE;
    }
    return TRUE;
}
Esempio n. 2
0
static int set_sw_params(snd_pcm_t *pcm,
                         snd_pcm_sw_params_t *sw_params,
                         snd_spcm_xrun_type_t xrun_type)
{
    int err;

    err = snd_pcm_sw_params_current(pcm, sw_params);
    if (err < 0)
        return err;
    err = snd_pcm_sw_params_set_start_threshold(pcm, sw_params, (pcm->buffer_size / pcm->period_size) * pcm->period_size);
    if (err < 0)
        return err;
    err = snd_pcm_sw_params_set_avail_min(pcm, sw_params, pcm->period_size);
    if (err < 0)
        return err;
    switch (xrun_type) {
    case SND_SPCM_XRUN_STOP:
        err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->buffer_size);
        break;
    case SND_SPCM_XRUN_IGNORE:
        err = snd_pcm_sw_params_set_stop_threshold(pcm, sw_params, pcm->boundary);
        break;
    default:
        return -EINVAL;
    }
    if (err < 0)
        return err;
    err = snd_pcm_sw_params_set_xfer_align(pcm, sw_params, 1);
    if (err < 0)
        return err;
    err = snd_pcm_sw_params(pcm, sw_params);
    if (err < 0)
        return err;
    return 0;
}
Esempio n. 3
0
int AudioAlsa::setSWParams()
{
	int err;

	// get the current swparams
	if( ( err = snd_pcm_sw_params_current( m_handle, m_swParams ) ) < 0 )
	{
		printf( "Unable to determine current swparams for playback: %s"
						"\n", snd_strerror( err ) );
		return err;
	}

	// start the transfer when a period is full
	if( ( err = snd_pcm_sw_params_set_start_threshold( m_handle,
					m_swParams, m_periodSize ) ) < 0 )
	{
		printf( "Unable to set start threshold mode for playback: %s\n",
							snd_strerror( err ) );
		return err;
	}

	// allow the transfer when at least m_periodSize samples can be
	// processed
	if( ( err = snd_pcm_sw_params_set_avail_min( m_handle, m_swParams,
							m_periodSize ) ) < 0 )
	{
		printf( "Unable to set avail min for playback: %s\n",
							snd_strerror( err ) );
		return err;
	}

	// align all transfers to 1 sample
	
#if SND_LIB_VERSION < ((1<<16)|(0)|16)
	if( ( err = snd_pcm_sw_params_set_xfer_align( m_handle,
							m_swParams, 1 ) ) < 0 )
	{
		printf( "Unable to set transfer align for playback: %s\n",
							snd_strerror( err ) );
		return err;
	}
#endif

	// write the parameters to the playback device
	if( ( err = snd_pcm_sw_params( m_handle, m_swParams ) ) < 0 )
	{
		printf( "Unable to set sw params for playback: %s\n",
							snd_strerror( err ) );
		return err;
	}

	return 0;	// all ok
}
int
set_mic_swparams(snd_pcm_t *handle) 
{
    // set software params

    snd_pcm_sw_params_t *swparams;
    snd_pcm_sw_params_alloca(&swparams);

    /* get the current swparams */
    int ret = snd_pcm_sw_params_current(handle, swparams);
    if (ret < 0) {
        fprintf(stderr, 
	    "Unable to determine current swparams for mic: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* allow transfer when at least period_frames can be processed */

    ret = snd_pcm_sw_params_set_avail_min(handle, swparams, 
	get_period_frames(handle));

    if (ret < 0) {
        fprintf(stderr, "Unable to set avail min for mic: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* align all transfers to 1 sample */
    ret = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
    if (ret < 0) {
        fprintf(stderr, "Unable to set transfer align for mic: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* write the parameters to the microphone device */
    ret = snd_pcm_sw_params(handle, swparams);
    if (ret < 0) {
        fprintf(stderr, "Unable to set sw params for mic: %s\n", 
	    snd_strerror(ret));
        return ret;
    }
	
    dump_swparams(handle);
    return 0;
}
/* setup alsa data transfer behavior */
static inline int alsa_set_swparams(ao_alsa_internal *internal)
{
	snd_pcm_sw_params_t   *params;
	int err;

	/* allocate the software parameter structure */
	snd_pcm_sw_params_alloca(&params);

	/* fetch the current software parameters */
	internal->cmd = "snd_pcm_sw_params_current";
	err = snd_pcm_sw_params_current(internal->pcm_handle, params);
	if (err < 0)
		return err;

	/* allow transfers to start when there is one period */
	internal->cmd = "snd_pcm_sw_params_set_start_threshold";
	err = snd_pcm_sw_params_set_start_threshold(internal->pcm_handle,
			params, internal->period_size);
	if (err < 0)
		return err;

	/* require a minimum of one full transfer in the buffer */
	internal->cmd = "snd_pcm_sw_params_set_avail_min";
	err = snd_pcm_sw_params_set_avail_min(internal->pcm_handle, params,
			internal->period_size);
	if (err < 0)
		return err;

	/* do not align transfers */
	internal->cmd = "snd_pcm_sw_params_set_xfer_align";
	err = snd_pcm_sw_params_set_xfer_align(internal->pcm_handle, params, 1);
	if (err < 0)
		return err;

	/* commit the params structure to ALSA */
	internal->cmd = "snd_pcm_sw_params";
	err = snd_pcm_sw_params(internal->pcm_handle, params);
	if (err < 0)
		return err;

	return 1;
}
Esempio n. 6
0
static int set_swparams(snd_pcm_t *handle, snd_pcm_sw_params_t *swparams, int period, int nperiods) {
	int err;

	/* get the current swparams */
	err = snd_pcm_sw_params_current(handle, swparams);
	if (err < 0) {
		printf("Unable to determine current swparams for capture: %s\n", snd_strerror(err));
		return err;
	}
	/* start the transfer when the buffer is full */
	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, period );
	if (err < 0) {
		printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err));
		return err;
	}
	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, -1 );
	if (err < 0) {
		printf("Unable to set start threshold mode for capture: %s\n", snd_strerror(err));
		return err;
	}
	/* allow the transfer when at least period_size samples can be processed */
	err = snd_pcm_sw_params_set_avail_min(handle, swparams, 1 );
	if (err < 0) {
		printf("Unable to set avail min for capture: %s\n", snd_strerror(err));
		return err;
	}
	/* align all transfers to 1 sample */
	err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
	if (err < 0) {
		printf("Unable to set transfer align for capture: %s\n", snd_strerror(err));
		return err;
	}
	/* write the parameters to the playback device */
	err = snd_pcm_sw_params(handle, swparams);
	if (err < 0) {
		printf("Unable to set sw params for capture: %s\n", snd_strerror(err));
		return err;
	}
	return 0;
}
Esempio n. 7
0
int
sound_lowlevel_init( const char *device, int *freqptr, int *stereoptr )
{
  unsigned int exact_rate, periods;
  unsigned int val, n;
  snd_pcm_hw_params_t *hw_params;
  snd_pcm_sw_params_t *sw_params;
  snd_pcm_uframes_t avail_min = 0, sound_periodsize, bsize = 0;
  static int first_init = 1;
  static int init_running = 0;
  const char *option;
  char tmp;
  int err, dir, nperiods = NUM_FRAMES;

  float hz;

  if( init_running )
    return 0;
  
  init_running = 1;
/* select a default device if we weren't explicitly given one */

  option = device;
  while( option && *option ) {
    tmp = '*';
    if( ( err = sscanf( option, " buffer=%i %n%c", &val, &n, &tmp ) > 0 ) &&
		( tmp == ',' || strlen( option ) == n ) ) {
      if( val < 1 ) {
	fprintf( stderr, "Bad value for ALSA buffer size %i, using default\n",
		    val );
      } else {
        bsize = val;
      }
    } else if( ( err = sscanf( option, " frames=%i %n%c", &val, &n, &tmp ) > 0 ) &&
		( tmp == ',' || strlen( option ) == n ) ) {
      if( val < 1 ) {
	fprintf( stderr, "Bad value for ALSA buffer size %i frames, using default (%d)\n",
		    val, NUM_FRAMES );
      } else {
        nperiods = val;
      }
    } else if( ( err = sscanf( option, " avail=%i %n%c", &val, &n, &tmp ) > 0 ) &&
		( tmp == ',' || strlen( option ) == n ) ) {
      if( val < 1 ) {
	fprintf( stderr, "Bad value for ALSA avail_min size %i frames, using default\n",
		    val );
      } else {
        avail_min = val;
      }
    } else if( ( err = sscanf( option, " verbose %n%c", &n, &tmp ) == 1 ) &&
		( tmp == ','  || strlen( option ) == n ) ) {
      verb = 1;
    } else {					/* try as device name */
	while( isspace(*option) )
          option++;
	if( *option == '\'' )		/* force device... */
	  option++;
	pcm_name = option;
	n = strlen( pcm_name );
    }
    option += n + ( tmp == ',' );
  }

/* Open the sound device
 */
  if( pcm_name == NULL || *pcm_name == '\0' )
    pcm_name = "default";
  if( snd_pcm_open( &pcm_handle, pcm_name , stream, 0 ) < 0 ) {
    if( strcmp( pcm_name, "default" ) == 0 ) {
    /* we try a last one: plughw:0,0 but what a weired ALSA conf.... */
      if( snd_pcm_open( &pcm_handle, "plughw:0,0", stream, 0 ) < 0 ) {
        settings_current.sound = 0;
        ui_error( UI_ERROR_ERROR,
                  "couldn't open sound device 'default' and 'plughw:0,0' check ALSA configuration."
                  );
	init_running = 0;
        return 1;
      } else {
        if( first_init )
          fprintf( stderr,
                    "Couldn't open sound device 'default', using 'plughw:0,0' check ALSA configuration.\n"
                    );
      }
    }
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't open sound device '%s'.", pcm_name );
    init_running = 0;
    return 1;
  }

/* Allocate the snd_pcm_hw_params_t structure on the stack. */
  snd_pcm_hw_params_alloca( &hw_params );

/* Init hw_params with full configuration space */
  if( snd_pcm_hw_params_any( pcm_handle, hw_params ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR,
              "couldn't get configuration space on sound device '%s'.",
              pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( snd_pcm_hw_params_set_access( pcm_handle, hw_params,
                                    SND_PCM_ACCESS_RW_INTERLEAVED ) < 0) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set access interleaved on '%s'.",
              pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }
  
    /* Set sample format */
  if( snd_pcm_hw_params_set_format( pcm_handle, hw_params, 
#if defined WORDS_BIGENDIAN
				    SND_PCM_FORMAT_S16_BE
#else
				    SND_PCM_FORMAT_S16_LE
#endif
						    ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set format on '%s'.", pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  ch = *stereoptr ? 2 : 1;

  if( snd_pcm_hw_params_set_channels( pcm_handle, hw_params, ch )
	    < 0 ) {
    fprintf( stderr, "Couldn't set %s to '%s'.\n", pcm_name,
    		    (*stereoptr ? "stereo" : "mono") );
    ch = *stereoptr ? 1 : 2;		/* try with opposite */
    if( snd_pcm_hw_params_set_channels( pcm_handle, hw_params, ch )
	    < 0 ) {
      ui_error( UI_ERROR_ERROR, "couldn't set %s to '%s'.", pcm_name,
    		    (*stereoptr ? "stereo" : "mono") );
      settings_current.sound = 0;
      snd_pcm_close( pcm_handle );
      init_running = 0;
      return 1;
    }
    *stereoptr = *stereoptr ? 0 : 1;		/* write back */
  }

  framesize = ch << 1;			/* we always use 16 bit sorry :-( */
/* Set sample rate. If the exact rate is not supported */
/* by the hardware, use nearest possible rate.         */ 
  exact_rate = *freqptr;
  if( snd_pcm_hw_params_set_rate_near( pcm_handle, hw_params, &exact_rate,
							NULL ) < 0) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set rate %d on '%s'.",
						*freqptr, pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }
  if( first_init && *freqptr != exact_rate ) {
    fprintf( stderr, 
              "The rate %d Hz is not supported by your hardware. "
              "Using %d Hz instead.\n", *freqptr, exact_rate );
    *freqptr = exact_rate;
  }

  if( bsize != 0 ) {
    exact_periodsize = sound_periodsize = bsize / nperiods;
    if( bsize < 1 ) {
      fprintf( stderr,
                "bad value for ALSA buffer size %i, using default.\n",
		val );
      bsize = 0;
    }
  }

  if( bsize == 0 ) {
    /* Adjust relative processor speed to deal with adjusting sound generation
       frequency against emulation speed (more flexible than adjusting generated
       sample rate) */
    hz = (float)sound_get_effective_processor_speed() /
              machine_current->timings.tstates_per_frame;
    /* Amount of audio data we will accumulate before yielding back to the OS.
       Not much point having more than 100Hz playback, we probably get
       downgraded by the OS as being a hog too (unlimited Hz limits playback
       speed to about 2000% on my Mac, 100Hz allows up to 5000% for me) */
    if( hz > 100.0 ) hz = 100.0;
    exact_periodsize = sound_periodsize = *freqptr / hz;
  }

  dir = -1;
  if( snd_pcm_hw_params_set_period_size_near( pcm_handle, hw_params,
					    &exact_periodsize, &dir ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set period size %d on '%s'.",
                              (int)sound_periodsize, pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( first_init && ( exact_periodsize < sound_periodsize / 1.5 ||
		      exact_periodsize > sound_periodsize * 1.5    ) ) {
    fprintf( stderr,
              "The period size %d is not supported by your hardware. "
              "Using %d instead.\n", (int)sound_periodsize,
              (int)exact_periodsize );
  }

  periods = nperiods;
/* Set number of periods. Periods used to be called fragments. */
  if( snd_pcm_hw_params_set_periods_near( pcm_handle, hw_params, &periods,
                                          NULL ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR, "couldn't set periods on '%s'.", pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( first_init && periods != nperiods ) {
    fprintf( stderr, "%d periods is not supported by your hardware. "
                    	     "Using %d instead.\n", nperiods, periods );
  }

  snd_pcm_hw_params_get_buffer_size( hw_params, &exact_bsize );

  /* Apply HW parameter settings to */
  /* PCM device and prepare device  */

  if( snd_pcm_hw_params( pcm_handle, hw_params ) < 0 ) {
    settings_current.sound = 0;
    ui_error( UI_ERROR_ERROR,"couldn't set hw_params on %s", pcm_name );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  snd_pcm_sw_params_alloca( &sw_params );
  if( ( err = snd_pcm_sw_params_current( pcm_handle, sw_params ) ) < 0 ) {
    ui_error( UI_ERROR_ERROR,"couldn't get sw_params from %s: %s", pcm_name,
              snd_strerror ( err ) );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( ( err = snd_pcm_sw_params_set_start_threshold( pcm_handle,
		     sw_params, exact_periodsize * ( nperiods - 1 ) ) ) < 0 ) {
    ui_error( UI_ERROR_ERROR,"couldn't set start_treshold on %s: %s", pcm_name,
              snd_strerror ( err ) );
    snd_pcm_close( pcm_handle );
    init_running = 0;
    return 1;
  }

  if( !avail_min )
    avail_min = exact_periodsize >> 1;
  if( snd_pcm_sw_params_set_avail_min( pcm_handle,
		    sw_params, avail_min ) < 0 ) {
#if SND_LIB_VERSION < 0x10010
    if( ( err = snd_pcm_sw_params_set_sleep_min( pcm_handle,
    		    sw_params, 1 ) ) < 0 ) {
	fprintf( stderr, "Unable to set minimal sleep 1 for %s: %s\n", pcm_name,
              snd_strerror ( err ) );
    }
#else
    fprintf( stderr, "Unable to set avail min %s: %s\n", pcm_name,
    	     snd_strerror( err ) );
#endif
  }

#if SND_LIB_VERSION < 0x10010
  if( ( err = snd_pcm_sw_params_set_xfer_align( pcm_handle, sw_params, 1 ) ) < 0 ) {
    ui_error( UI_ERROR_ERROR,"couldn't set xfer_allign on %s: %s", pcm_name,
              snd_strerror ( err ) );
    init_running = 0;
    return 1;
  }
#endif
  
  if( ( err = snd_pcm_sw_params( pcm_handle, sw_params ) ) < 0 ) {
    ui_error( UI_ERROR_ERROR,"couldn't set sw_params on %s: %s", pcm_name,
              snd_strerror ( err ) );
    init_running = 0;
    return 1;
  }

  if( first_init ) snd_output_stdio_attach(&output, stdout, 0);

  first_init = 0;
  init_running = 0;
  return 0;	/* success */
}
Esempio n. 8
0
static size_t
alsa_configure (void)
{
  //<init:
  size_t chunk_bytes, bits_per_sample, bits_per_frame = 0;
  snd_pcm_uframes_t chunk_size, buffer_size = 0;
  snd_pcm_hw_params_t *params;
  unsigned int rate = DEFAULT_SPEED;
  int err;
  snd_pcm_hw_params_alloca (&params);
  //>
  //<defaults:

  err = snd_pcm_hw_params_any (AHandle, params);
  if (err < 0)
    {
      fprintf (stderr,
               "Broken configuration for this PCM: no configurations available");
      exit (EXIT_FAILURE);
    }

  //>
  //<Format:

  err = snd_pcm_hw_params_set_format (AHandle, params, DEFAULT_FORMAT);
  if (err < 0)
    {
      fprintf (stderr, "Sample format non available");
      exit (EXIT_FAILURE);
    }

  //>
  //<Channels:

  err = snd_pcm_hw_params_set_channels (AHandle, params, 1);
  if (err < 0)
    {
      fprintf (stderr, "Channels count non available");
      exit (EXIT_FAILURE);
    }

  //>
  //<Rate:

  err = snd_pcm_hw_params_set_rate_near (AHandle, params, &rate, 0);
  assert (err >= 0);

  //>
  //<Access Mode:
  err = snd_pcm_hw_params_set_access (AHandle, params,
                                      SND_PCM_ACCESS_RW_INTERLEAVED);
  if (err < 0)
    {
      fprintf (stderr, "Access type not available");
      exit (EXIT_FAILURE);
    }
  //>
  //< Set things explicitly if DEBUG
#ifdef DEBUG

  //<Compute buffer_time:
  unsigned int period_time = 0;
  unsigned int buffer_time = 0;
  snd_pcm_uframes_t period_frames = 0;
  snd_pcm_uframes_t buffer_frames = 0;
  // affected by defined buffer_size  (e.g. via asoundrc)
  if (buffer_time == 0 && buffer_frames == 0)
    {
      err = snd_pcm_hw_params_get_buffer_time (params, &buffer_time, 0);
      assert (err >= 0);
      if (buffer_time > 500000) //usecs
        buffer_time = 500000;
    }
  //>
  //<Compute period_time:

  if (period_time == 0 && period_frames == 0)
    {
      if (buffer_time > 0)
        period_time = buffer_time / 4;
      else
        period_frames = buffer_frames / 4;
    }
  if (period_time > 0)
    err = snd_pcm_hw_params_set_period_time_near (AHandle, params,
                                                  &period_time, 0);
  else
    err = snd_pcm_hw_params_set_period_size_near (AHandle, params,
                                                  &period_frames, 0);
  assert (err >= 0);
  if (buffer_time > 0)
    {
      err = snd_pcm_hw_params_set_buffer_time_near (AHandle, params,
                                                    &buffer_time, 0);
    }
  else
    {
      err = snd_pcm_hw_params_set_buffer_size_near (AHandle, params,
                                                    &buffer_frames);
    }
  assert (err >= 0);

  //>
#endif

  //>
  //<Commit hw params:
  err = snd_pcm_hw_params (AHandle, params);
  if (err < 0)
    {
      fprintf (stderr, "Unable to install hw params:");
      exit (EXIT_FAILURE);
    }
  //>
  //<finalize chunk_size and buffer_size:

  snd_pcm_hw_params_get_period_size (params, &chunk_size, 0);
  snd_pcm_hw_params_get_buffer_size (params, &buffer_size);
  if (chunk_size == buffer_size)
    {
      fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)",
               chunk_size, buffer_size);
      exit (EXIT_FAILURE);
    }

  //>
  //< If DEBUG: SW Params Configure transfer:

#ifdef DEBUG
  size_t n;
  snd_pcm_uframes_t xfer_align;
  snd_pcm_uframes_t start_threshold, stop_threshold;
  int start_delay = 5;
  int stop_delay = 0;
  snd_pcm_sw_params_t *swParams;
  snd_pcm_sw_params_alloca (&swParams);
  snd_pcm_sw_params_current (AHandle, swParams);
  err = snd_pcm_sw_params_get_xfer_align (swParams, &xfer_align);
  if (err < 0)
    {
      fprintf (stderr, "Unable to obtain xfer align\n");
      exit (EXIT_FAILURE);
    }
  // round up to closest transfer boundary
  n = (buffer_size / xfer_align) * xfer_align;
  if (start_delay <= 0)
    {
      start_threshold =
        (snd_pcm_uframes_t) (n + (double) rate * start_delay / 1000000);
    }
  else
    start_threshold =
      (snd_pcm_uframes_t) ((double) rate * start_delay / 1000000);
  if (start_threshold < 1)
    start_threshold = 1;
  if (start_threshold > n)
    start_threshold = n;
  err =
    snd_pcm_sw_params_set_start_threshold (AHandle, swParams,
                                           start_threshold);
  assert (err >= 0);
  if (stop_delay <= 0)
    stop_threshold =
      (snd_pcm_uframes_t) (buffer_size +
                           (double) rate * stop_delay / 1000000);
  else
    stop_threshold =
      (snd_pcm_uframes_t) ((double) rate * stop_delay / 1000000);
  err =
    snd_pcm_sw_params_set_stop_threshold (AHandle, swParams, stop_threshold);
  assert (err >= 0);

  err = snd_pcm_sw_params_set_xfer_align (AHandle, swParams, xfer_align);
  assert (err >= 0);

  if (snd_pcm_sw_params (AHandle, swParams) < 0)
    {
      fprintf (stderr, "unable to install sw params:");
      exit (EXIT_FAILURE);
    }
#endif

  //>
  bits_per_sample = snd_pcm_format_physical_width (DEFAULT_FORMAT);
  bits_per_frame = bits_per_sample * 1; //mono
  chunk_bytes = chunk_size * bits_per_frame / 8;
  return chunk_bytes;
}
int
set_speaker_swparams(snd_pcm_t *handle, int channels, int bufferSize) 
{
    // set software params

    snd_pcm_sw_params_t *swparams;
    snd_pcm_sw_params_alloca(&swparams);

    int thresholdFrames;

    /* get the current swparams */
    int ret = snd_pcm_sw_params_current(handle, swparams);
    if (ret < 0) {
        fprintf(stderr, 
	    "Unable to determine current swparams for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* start the transfer when the second buffer is written
    ret = snd_pcm_sw_params_set_start_threshold(handle, swparams, 
	1 * period_frames);
    if (ret < 0) {
        fprintf(stderr, 
	    "Unable to set start threshold mode for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* Notify asynchronously when data can be written */
//    ret = snd_pcm_sw_params_set_avail_min(handle, swparams, 
//	get_period_frames(handle));

//    if (ret < 0) {
//        fprintf(stderr, "Unable to set avail min for playback: %s\n", 
//	    snd_strerror(ret));
//        return ret;
//    }

    /* align all transfers to 1 sample */
    ret = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
    if (ret < 0) {
        fprintf(stderr, "Unable to set transfer align for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    thresholdFrames = (bufferSize - 20) / 2 / channels;

    if (thresholdFrames <= 0) {
	thresholdFrames = bufferSize / 2 / channels;
    }

    fprintf(stderr, "speaker buffer size %d., thresholdFrames %d\n",
	 bufferSize, thresholdFrames);
 
    /* set silence threshold */
    ret = snd_pcm_sw_params_set_silence_threshold(handle, swparams, 
    	thresholdFrames);

    if (ret < 0) {
        fprintf(stderr, "Unable to set sw params for silence_threshold: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* set silence size */
    ret = snd_pcm_sw_params_set_silence_size(handle, swparams, 
	thresholdFrames);

    if (ret < 0) {
        fprintf(stderr, "Unable to set sw params for silence_size: %s\n", 
	    snd_strerror(ret));
        return ret;
    }

    /* write the parameters to the playback device */
    ret = snd_pcm_sw_params(handle, swparams);
    if (ret < 0) {
        fprintf(stderr, "Unable to set sw params for playback: %s\n", 
	    snd_strerror(ret));
        return ret;
    }
	
    dump_swparams(handle);
    return 0;
}
Esempio n. 10
0
/* alsa_init:
 *  ALSA init routine.
 */
static int alsa_init(int input, int voices)
{
   int ret = 0;
   char tmp1[128], tmp2[128];
   int format = 0;
   unsigned int numfrags = 0;
   snd_pcm_uframes_t fragsize;

   if (input) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Input is not supported"));
      return -1;
   }

   ALSA9_CHECK(snd_output_stdio_attach(&snd_output, stdout, 0));

   alsa_device = get_config_string(uconvert_ascii("sound", tmp1),
				   uconvert_ascii("alsa_device", tmp2),
				   alsa_device);

   alsa_mixer_device = get_config_string(uconvert_ascii("sound", tmp1),
				   uconvert_ascii("alsa_mixer_device", tmp2),
				   alsa_mixer_device);

   fragsize = get_config_int(uconvert_ascii("sound", tmp1),
			     uconvert_ascii("alsa_fragsize", tmp2), 0);

   numfrags = get_config_int(uconvert_ascii("sound", tmp1),
			     uconvert_ascii("alsa_numfrags", tmp2),
			     ALSA_DEFAULT_NUMFRAGS);

   ret = snd_pcm_open(&pcm_handle, alsa_device, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
   if (ret < 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not open card/pcm device"));
      return -1;
   }

   snd_mixer_open(&alsa_mixer, 0);

   if (alsa_mixer
       && snd_mixer_attach(alsa_mixer, alsa_mixer_device) >= 0
       && snd_mixer_selem_register (alsa_mixer, NULL, NULL) >= 0
       && snd_mixer_load(alsa_mixer) >= 0) {
      const char *alsa_mixer_elem_name = get_config_string(uconvert_ascii("sound", tmp1),
							   uconvert_ascii("alsa_mixer_elem", tmp2),
							   "PCM");

      alsa_mixer_elem = snd_mixer_first_elem(alsa_mixer);

      while (alsa_mixer_elem) {
	 const char *name = snd_mixer_selem_get_name(alsa_mixer_elem);

	 if (strcasecmp(name, alsa_mixer_elem_name) == 0) {
	    snd_mixer_selem_get_playback_volume_range(alsa_mixer_elem, &alsa_mixer_elem_min, &alsa_mixer_elem_max);
	    alsa_mixer_allegro_ratio = (double) (alsa_mixer_elem_max - alsa_mixer_elem_min) / (double) 255;
	    break;
	 }

	 alsa_mixer_elem = snd_mixer_elem_next(alsa_mixer_elem);
      }
   }

   /* Set format variables. */
   alsa_bits = (_sound_bits == 8) ? 8 : 16;
   alsa_stereo = (_sound_stereo) ? 1 : 0;
   alsa_rate = (_sound_freq > 0) ? _sound_freq : 44100;
   alsa_signed = 0;

   format = ((alsa_bits == 16) ? SND_PCM_FORMAT_U16_NE : SND_PCM_FORMAT_U8);

   switch (format) {

      case SND_PCM_FORMAT_U8:
	 alsa_bits = 8;
	 break;

      case SND_PCM_FORMAT_U16_NE:
	 if (sizeof(short) != 2) {
	    ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
	    goto Error;
	 }
	 break;

      default:
	 ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Unsupported sample format"));
	 goto Error;
   }

   alsa_sample_size = (alsa_bits / 8) * (alsa_stereo ? 2 : 1);

   if (fragsize == 0) {
      unsigned int size = alsa_rate * ALSA_DEFAULT_BUFFER_MS / 1000 / numfrags;
      fragsize = 1;
      while (fragsize < size)
	 fragsize <<= 1;
   }

   snd_pcm_hw_params_malloc(&hwparams);
   snd_pcm_sw_params_malloc(&swparams);

   ALSA9_CHECK(snd_pcm_hw_params_any(pcm_handle, hwparams));
   ALSA9_CHECK(snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED));
   ALSA9_CHECK(snd_pcm_hw_params_set_format(pcm_handle, hwparams, format));
   ALSA9_CHECK(snd_pcm_hw_params_set_channels(pcm_handle, hwparams, alsa_stereo + 1));

   ALSA9_CHECK(snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &alsa_rate, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &fragsize, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &numfrags, NULL)); 

   ALSA9_CHECK(snd_pcm_hw_params(pcm_handle, hwparams));

   ALSA9_CHECK(snd_pcm_hw_params_get_period_size(hwparams, &alsa_bufsize, NULL));
   ALSA9_CHECK(snd_pcm_hw_params_get_periods(hwparams, &alsa_fragments, NULL));

   TRACE (PREFIX_I "alsa_bufsize = %ld, alsa_fragments = %d\n", alsa_bufsize, alsa_fragments);

   ALSA9_CHECK(snd_pcm_sw_params_current(pcm_handle, swparams));
   ALSA9_CHECK(snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, alsa_bufsize));
   ALSA9_CHECK(snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, fragsize));
   ALSA9_CHECK(snd_pcm_sw_params_set_xfer_align(pcm_handle, swparams, 1));
   ALSA9_CHECK(snd_pcm_sw_params(pcm_handle, swparams));

   /* Allocate mixing buffer. */
   alsa_bufdata = _AL_MALLOC_ATOMIC(alsa_bufsize * alsa_sample_size);
   if (!alsa_bufdata) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not allocate audio buffer"));
      goto Error;
   }

   /* Initialise mixer. */
   digi_alsa.voices = voices;

   if (_mixer_init(alsa_bufsize * (alsa_stereo ? 2 : 1), alsa_rate,
		   alsa_stereo, ((alsa_bits == 16) ? 1 : 0),
		   &digi_alsa.voices) != 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Can not init software mixer"));
      goto Error;
   }

   snd_pcm_prepare(pcm_handle);
   pdc = snd_pcm_poll_descriptors_count (pcm_handle);
   if (pdc <= 0) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Invalid poll descriptors count"));
      goto Error;
   }

   ufds = _AL_MALLOC(sizeof(struct pollfd) * pdc);
   if (ufds == NULL) {
      ustrzcpy(allegro_error, ALLEGRO_ERROR_SIZE, get_config_text("Not enough memory for poll descriptors"));
      goto Error;
   }
   ALSA9_CHECK(snd_pcm_poll_descriptors(pcm_handle, ufds, pdc));

   poll_next = 0;

   _mix_some_samples((uintptr_t) alsa_bufdata, 0, alsa_signed);

   /* Add audio interrupt. */
   _unix_bg_man->register_func(alsa_update);

   uszprintf(alsa_desc, sizeof(alsa_desc),
	     get_config_text
	     ("Alsa 0.9, Device '%s': %d bits, %s, %d bps, %s"),
	     alsa_device, alsa_bits,
	     uconvert_ascii((alsa_signed ? "signed" : "unsigned"), tmp1),
	     alsa_rate, uconvert_ascii((alsa_stereo ? "stereo" : "mono"), tmp2));

   digi_driver->desc = alsa_desc;
   return 0;

 Error:
   if (pcm_handle) {
      snd_pcm_close(pcm_handle);
      pcm_handle = NULL;
   }

   return -1;
}
Esempio n. 11
0
static void set_params(void)
{
	snd_pcm_hw_params_t *params;
	snd_pcm_sw_params_t *swparams;
	snd_pcm_uframes_t buffer_size;
	int err;
	size_t n;
	snd_pcm_uframes_t xfer_align;
	unsigned int rate;
	snd_pcm_uframes_t start_threshold, stop_threshold;
	snd_pcm_hw_params_alloca(&params);
	snd_pcm_sw_params_alloca(&swparams);
	err = snd_pcm_hw_params_any(handle, params);
	if (err < 0) {
		error(_("Broken configuration for this PCM: no configurations available"));
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
	if (err < 0) {
		error(_("Access type not available"));
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_format(handle, params, hwparams.format);
	if (err < 0) {
		error(_("Sample format non available"));
		exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels);
	if (err < 0) {
		error(_("Channels count non available"));
		exit(EXIT_FAILURE);
	}

#if 0
	err = snd_pcm_hw_params_set_periods_min(handle, params, 2);
	assert(err >= 0);
#endif
	rate = hwparams.rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0);
	assert(err >= 0);
	if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) {
		if (!quiet_mode) {
			char plugex[64];
			const char *pcmname = snd_pcm_name(handle);
			fprintf(stderr, _("Warning: rate is not accurate (requested = %iHz, got = %iHz)\n"), rate, hwparams.rate);
			if (! pcmname || strchr(snd_pcm_name(handle), ':'))
				*plugex = 0;
			else
				snprintf(plugex, sizeof(plugex), "(-Dplug:%s)",
					 snd_pcm_name(handle));
			fprintf(stderr, _("         please, try the plug plugin %s\n"),
				plugex);
		}
	}
	rate = hwparams.rate;
	if (buffer_time == 0 && buffer_frames == 0) {
		err = snd_pcm_hw_params_get_buffer_time_max(params,
							    &buffer_time, 0);
		assert(err >= 0);
		if (buffer_time > 500000)
			buffer_time = 500000;
	}
	if (period_time == 0 && period_frames == 0) {
		if (buffer_time > 0)
			period_time = buffer_time / 4;
		else
			period_frames = buffer_frames / 4;
	}
	if (period_time > 0)
		err = snd_pcm_hw_params_set_period_time_near(handle, params,
							     &period_time, 0);
	else
		err = snd_pcm_hw_params_set_period_size_near(handle, params,
							     &period_frames, 0);
	assert(err >= 0);
	if (buffer_time > 0) {
		err = snd_pcm_hw_params_set_buffer_time_near(handle, params,
							     &buffer_time, 0);
	} else {
		err = snd_pcm_hw_params_set_buffer_size_near(handle, params,
							     &buffer_frames);
	}
	assert(err >= 0);
	err = snd_pcm_hw_params(handle, params);
	if (err < 0) {
		error(_("Unable to install hw params:"));
		snd_pcm_hw_params_dump(params, log);
		exit(EXIT_FAILURE);
	}
	snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
	snd_pcm_hw_params_get_buffer_size(params, &buffer_size);
	if (chunk_size == buffer_size) {
		error(_("Can't use period equal to buffer size (%lu == %lu)"),
		      chunk_size, buffer_size);
		exit(EXIT_FAILURE);
	}
	snd_pcm_sw_params_current(handle, swparams);
	err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);
	if (err < 0) {
		error(_("Unable to obtain xfer align\n"));
		exit(EXIT_FAILURE);
	}
	if (sleep_min)
		xfer_align = 1;
	err = snd_pcm_sw_params_set_sleep_min(handle, swparams,
					      sleep_min);
	assert(err >= 0);
	if (avail_min < 0)
		n = chunk_size;
	else
		n = (double) rate * avail_min / 1000000;
	err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);

	// round up to closest transfer boundary
	n = (buffer_size / xfer_align) * xfer_align;
	start_threshold = n;
	if (start_threshold < 1)
		start_threshold = 1;
	if (start_threshold > n)
		start_threshold = n;
	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);
	assert(err >= 0);
	stop_threshold = buffer_size;
	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);
	assert(err >= 0);

	err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);
	assert(err >= 0);

	if (snd_pcm_sw_params(handle, swparams) < 0) {
		error(_("unable to install sw params:"));
		snd_pcm_sw_params_dump(swparams, log);
		exit(EXIT_FAILURE);
	}

	bits_per_sample = snd_pcm_format_physical_width(hwparams.format);
	bits_per_frame = bits_per_sample * hwparams.channels;
	chunk_bytes = chunk_size * bits_per_frame / 8;
	audiobuf = realloc(audiobuf, chunk_bytes);
	if (audiobuf == NULL) {
		error(_("not enough memory"));
		exit(EXIT_FAILURE);
	}
	// fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size);
}
Esempio n. 12
0
static gboolean
alsa_open (void *dp)
{
    alsa_driver * const d = dp;
    gint mf, err, pers;

    if(pcm_open_and_load_hwparams(d) < 0)
	goto out;

    // ---
    // Set non-blocking mode.
    // ---

    d->outtime = 0;

    // --
    // Set channel parameters
    // --
    if((err = snd_pcm_hw_params_set_access(d->soundfd, d->hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
	alsa_error(N_("Unable to set access"), err);
	goto out;
    }

    if((err = snd_pcm_hw_params_set_format(d->soundfd, d->hwparams,
				    (d->bits - 8) ? d->signedness16 ? SND_PCM_FORMAT_S16 : SND_PCM_FORMAT_U16 :
						    d->signedness8 ? SND_PCM_FORMAT_S8 : SND_PCM_FORMAT_U8) < 0)) {
	alsa_error(N_("Unable to set audio format"), err);
	goto out;
    }
    /* Handle endianess aspects. TODO! */
    switch(d->bits) {
	case 16:
	    mf = d->signedness16 ? ST_MIXER_FORMAT_S16_LE : ST_MIXER_FORMAT_U16_LE;
	    break;
	case 8:
	default:
	    mf = d->signedness8 ? ST_MIXER_FORMAT_S8 : ST_MIXER_FORMAT_U8;
	    break;
    }

    if((err = snd_pcm_hw_params_set_channels(d->soundfd, d->hwparams, d->stereo + 1)) < 0) {
	alsa_error(N_("Unable to set channels number"), err);
	goto out;
    }
    if((d->stereo)) {
	mf |= ST_MIXER_FORMAT_STEREO;
    }
    d->mf = mf;

    d->p_mixfreq = d->playrate;
    if ((err = snd_pcm_hw_params_set_rate_near(d->soundfd, d->hwparams, &(d->p_mixfreq), NULL)) < 0) {
	alsa_error(N_("Unable to set sample rate"), err);
	goto out;
    }

    if(snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size) < 0) {
	/* Some soundcards report wrong maximal buffer size (maybe alsa bug). So we should try
	   to downscale its value before the reporting an error. The spinbutton still may display
	   the wrong number, but actually the correct value will be implemented.*/
	while((--d->buffer_size) >= 8)
	    if(!snd_pcm_hw_params_set_buffer_size(d->soundfd, d->hwparams, 1 << d->buffer_size))
		break;
	if(d->buffer_size < 8) {
	    error_error(N_("Unable to set appropriate buffer size"));
	    goto out;
	}
    }
    pers = 1 << d->num_periods;
    if ((err = snd_pcm_hw_params_set_periods_near(d->soundfd, d->hwparams, &pers, NULL)) < 0) {
	alsa_error(N_("Unable to set periods number"), err);
	goto out;
    }
    if ((err = snd_pcm_hw_params_get_period_size(d->hwparams, &(d->p_fragsize), NULL)) < 0) {
	alsa_error(N_("Unable to get period size"), err);
	goto out;
    }

    if((err = snd_pcm_hw_params(d->soundfd, d->hwparams))) {
	alsa_error(N_("Error setting hw parameters"), err);
	goto out;
    }

    /* The following piece of code is directly c_n_p'ed from the ALSA pcm example (whith a little adopting) */
    /* get the current swparams */
    err = snd_pcm_sw_params_current(d->soundfd, d->swparams);
    if (err < 0) {
            alsa_error(N_("Unable to determine current swparams for playback"), err);
	    goto out;
    }
    /* start the transfer when the buffer is full */
    err = snd_pcm_sw_params_set_start_threshold(d->soundfd, d->swparams, d->p_fragsize);
    if (err < 0) {
            alsa_error(N_("Unable to set start threshold mode for playback"), err);
	    goto out;
    }
    /* allow the transfer when at least period_size samples can be processed */
    err = snd_pcm_sw_params_set_avail_min(d->soundfd, d->swparams, d->p_fragsize);
    if (err < 0) {
            alsa_error(N_("Unable to set avail min for playback"), err);
	    goto out;
    }
    /* align all transfers to 1 sample */
    err = snd_pcm_sw_params_set_xfer_align(d->soundfd, d->swparams, 1);
    if (err < 0) {
            alsa_error(N_("Unable to set transfer align for playback"), err);
	    goto out;
    }
    /* write the parameters to the playback device */
    err = snd_pcm_sw_params(d->soundfd, d->swparams);
    if (err < 0) {
            alsa_error(N_("Unable to set sw params for playback"), err);
	    goto out;
    }

    err = snd_pcm_prepare(d->soundfd);
    if (err < 0) {
            alsa_error(N_("Unable to prepare playback"), err);
	    goto out;
    }
    // ---
    // Get buffering parameters
    // ---
   
    if(d->verbose)
        snd_pcm_dump(d->soundfd, d->output);
    d->sndbuf = calloc((d->stereo + 1) * (d->bits / 8), d->p_fragsize);

    d->pfd = malloc(sizeof(struct pollfd));
    if ((err = snd_pcm_poll_descriptors(d->soundfd, d->pfd, 1)) < 0) {
        alsa_error(N_("Unable to obtain poll descriptors for playback"), err);
        goto out;
    }

    d->polltag = audio_poll_add(d->pfd->fd, GDK_INPUT_WRITE, alsa_poll_ready_playing, d);

    d->playtime = 0;
    d->firstpoll = TRUE;

    return TRUE;

  out:
    alsa_release(dp);
    return FALSE;
}
Esempio n. 13
0
/* setup alsa data transfer behavior */
static inline int alsa_set_swparams(ao_device *device)
{
	ao_alsa_internal *internal  = (ao_alsa_internal *) device->internal;
	snd_pcm_sw_params_t *params;
        snd_pcm_uframes_t boundary;
	int err;

	/* allocate the software parameter structure */
	snd_pcm_sw_params_alloca(&params);

	/* fetch the current software parameters */
	err = snd_pcm_sw_params_current(internal->pcm_handle, params);
	if (err < 0){
          adebug("snd_pcm_sw_params_current() failed.\n");
          return err;
        }

#if 0 /* the below causes more trouble than it cures */
	/* allow transfers to start when there is one period */
	err = snd_pcm_sw_params_set_start_threshold(internal->pcm_handle,
                                                    params, internal->period_size);
	if (err < 0){
          adebug("snd_pcm_sw_params_set_start_threshold() failed.\n");
          //return err;
        }

	/* require a minimum of one full transfer in the buffer */
	err = snd_pcm_sw_params_set_avail_min(internal->pcm_handle, params,
                                              internal->period_size);
	if (err < 0){
          adebug("snd_pcm_sw_params_set_avail_min() failed.\n");
          //return err;
        }
#endif

	/* do not align transfers; this is obsolete/deprecated in ALSA
           1.x where the transfer alignemnt is always 1 (except for
           buggy drivers like VIA 82xx which still demand aligned
           transfers regardless of setting, in violation of the ALSA
           API docs) */
	err = snd_pcm_sw_params_set_xfer_align(internal->pcm_handle, params, 1);
	if (err < 0){
          adebug("snd_pcm_sw_params_set_xfer_align() failed.\n");
          //return err;
        }


        /* get the boundary size */
        err = snd_pcm_sw_params_get_boundary(params,&boundary);
	if (err < 0){
          adebug("snd_pcm_sw_params_get_boundary() failed.\n");
        }else{

          /* force a work-ahead silence buffer; this is a fix, again for
             VIA 82xx, where non-MMIO transfers will buffer into
             period-size transfers, but the last transfer is usually
             undersized and playback falls off the end of the submitted
             data. */
          err = snd_pcm_sw_params_set_silence_size(internal->pcm_handle, params, boundary);
          if (err < 0){
            adebug("snd_pcm_sw_params_set_silence_size() failed.\n");
            //return err;
          }
        }

	/* commit the params structure to ALSA */
	err = snd_pcm_sw_params(internal->pcm_handle, params);
	if (err < 0){
          adebug("snd_pcm_sw_params() failed.\n");
          return err;
        }

	return 1;
}
Esempio n. 14
0
static int
set_swparams (GstAlsaSrc * alsa)
{
  int err;
  snd_pcm_sw_params_t *params;

  snd_pcm_sw_params_malloc (&params);

  /* get the current swparams */
  CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config);
  /* allow the transfer when at least period_size samples can be processed */
  CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params,
          alsa->period_size), set_avail);
  /* start the transfer on first read */
  CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params,
          0), start_threshold);
  /* use monotonic timestamping */
  CHECK (snd_pcm_sw_params_set_tstamp_mode (alsa->handle, params,
          SND_PCM_TSTAMP_MMAP), tstamp_mode);

#if GST_CHECK_ALSA_VERSION(1,0,16)
  /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */
#else
  /* align all transfers to 1 sample */
  CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align);
#endif

  /* write the parameters to the recording device */
  CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);

  snd_pcm_sw_params_free (params);
  return 0;

  /* ERRORS */
no_config:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Unable to determine current swparams for playback: %s",
            snd_strerror (err)));
    snd_pcm_sw_params_free (params);
    return err;
  }
start_threshold:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Unable to set start threshold mode for playback: %s",
            snd_strerror (err)));
    snd_pcm_sw_params_free (params);
    return err;
  }
set_avail:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Unable to set avail min for playback: %s", snd_strerror (err)));
    snd_pcm_sw_params_free (params);
    return err;
  }
tstamp_mode:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Unable to set tstamp mode for playback: %s", snd_strerror (err)));
    snd_pcm_sw_params_free (params);
    return err;
  }
#if !GST_CHECK_ALSA_VERSION(1,0,16)
set_align:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Unable to set transfer align for playback: %s", snd_strerror (err)));
    snd_pcm_sw_params_free (params);
    return err;
  }
#endif
set_sw_params:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Unable to set sw params for playback: %s", snd_strerror (err)));
    snd_pcm_sw_params_free (params);
    return err;
  }
}
Esempio n. 15
0
int setparams_set(snd_pcm_t *handle,
		  snd_pcm_hw_params_t *params,
		  snd_pcm_sw_params_t *swparams,
		  const char *id)
{
	int err;
	snd_pcm_uframes_t val;
	unsigned int sleep_min = 0;

	err = snd_pcm_hw_params(handle, params);
	if (err < 0) {
		printf("Unable to set hw params for %s: %s\n", id, snd_strerror(err));
		return err;
	}
	err = snd_pcm_sw_params_current(handle, swparams);
	if (err < 0) {
		printf("Unable to determine current swparams for %s: %s\n", id, snd_strerror(err));
		return err;
	}
	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0x7fffffff);
	if (err < 0) {
		printf("Unable to set start threshold mode for %s: %s\n", id, snd_strerror(err));
		return err;
	}
	tick_time_ok = 0;
	if (tick_time > 0) {
		int time, ttime;
		snd_pcm_hw_params_get_period_time(params, &time, NULL);
		 snd_pcm_hw_params_get_tick_time(params, &ttime, NULL);
		if (time < ttime) {
			printf("Skipping to set minimal sleep: period time < tick time\n");
		} else if (ttime <= 0) {
			printf("Skipping to set minimal sleep: tick time <= 0 (%i)\n", ttime);
		} else {
			sleep_min = tick_time / ttime;
			if (sleep_min <= 0)
				sleep_min = 1;
			err = snd_pcm_sw_params_set_sleep_min(handle, swparams, sleep_min);
			if (err < 0) {
				printf("Unable to set minimal sleep %i for %s: %s\n", sleep_min, id, snd_strerror(err));
				return err;
			}
			tick_time_ok = sleep_min * ttime;
		}
	}
	if (!block)
		val = 4;
	else
		snd_pcm_hw_params_get_period_size(params, &val, NULL);
	if (tick_time_ok > 0)
		val = 16;
	err = snd_pcm_sw_params_set_avail_min(handle, swparams, val);
	if (err < 0) {
		printf("Unable to set avail min for %s: %s\n", id, snd_strerror(err));
		return err;
	}
	val = !block ? 4 : 1;
	err = snd_pcm_sw_params_set_xfer_align(handle, swparams, val);
	if (err < 0) {
		printf("Unable to set transfer align for %s: %s\n", id, snd_strerror(err));
		return err;
	}
	err = snd_pcm_sw_params(handle, swparams);
	if (err < 0) {
		printf("Unable to set sw params for %s: %s\n", id, snd_strerror(err));
		return err;
	}
	return 0;
}
Esempio n. 16
0
bool QAudioInputPrivate::open( QObject *input )
{
    // Open the Alsa capture device.
    bool    rc = true;
    int     err;

    unsigned int        freakuency = frequency;

    if ((err = snd_pcm_open(&handle,
                             m_device.constData(), //"plughw:0,0"
                             SND_PCM_STREAM_CAPTURE,
                                 0/*SND_PCM_ASYNC*/)) < 0) {

        qWarning( "QAudioInput: snd_pcm_open: error %d", err);

        rc = false;
    }
    else {
        snd_pcm_hw_params_t *hwparams;

        // We want non-blocking mode.
        snd_pcm_nonblock(handle, 1);

        // Set the desired parameters.
        snd_pcm_hw_params_alloca(&hwparams);

        err = snd_pcm_hw_params_any(handle, hwparams);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_any: err %d", err);
        }

        err = snd_pcm_hw_params_set_access(handle, hwparams,
                                           access);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_set_access: err %d",err);
        }

        err = snd_pcm_hw_params_set_format(handle, hwparams,format);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_set_format: err %d",err);
        }

        err = snd_pcm_hw_params_set_channels(handle,hwparams,(unsigned int)channels);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_set_channels: err %d",err);
        }

        err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &freakuency, 0);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_set_rate_near: err %d",err);
        }
        if(freakuency > 1.05 * frequency || freakuency < 0.95 * frequency) {
            qWarning("QAudioInput: warning, sample rate %i not supported by the hardware, using %u", frequency, freakuency);
        }

        if ( samplesPerBlock != -1 ) {
            // Set buffer and period sizes based on the supplied block size.
            sample_size = (snd_pcm_uframes_t)( samplesPerBlock * channels / 8 );
            err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &freakuency, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_rate_near: err %d",err);
            }
            if(freakuency > 1.05 * frequency || freakuency < 0.95 * frequency) {
                qWarning( "QAudioInput: warning, sample rate %i not supported by the hardware, using %u", frequency, freakuency);
            }

            err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err %d",err);
            }
            period_time = 1000000 * 256 / frequency;
            err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_period_time_near: err %d",err);
            }
        } else {
            // Use the largest buffer and period sizes we can.
            err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err %d",err);
            }
            period_time = 1000000 * 256 / frequency;
            err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_period_time_near: err %d",err);
            }
       }

        err = snd_pcm_hw_params(handle, hwparams);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params: err %d",err);
        }

        int                  dir;
        unsigned int         vval, vval2;
        snd_pcm_access_t     aval;
        snd_pcm_format_t     fval;
        snd_pcm_subformat_t  sval;

        qLog(QAudioInput) << "PCM handle name = " << snd_pcm_name(handle);
        qLog(QAudioInput) << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle));

        snd_pcm_hw_params_get_access(hwparams,&aval);
        vval = (unsigned int)aval;
        if ( (int)vval != (int)access ) {
            qLog(QAudioInput) << QString("access type not set, want %1 got %2")
                       .arg(snd_pcm_access_name((snd_pcm_access_t)access))
                       .arg(snd_pcm_access_name((snd_pcm_access_t)vval));
            access = (snd_pcm_access_t)vval;
        }
        qLog(QAudioInput) << "access type = " << snd_pcm_access_name((snd_pcm_access_t)vval);

        snd_pcm_hw_params_get_format(hwparams, &fval);
        vval = (unsigned int)fval;
        if ( (int)vval != (int)format ) {
            qLog(QAudioInput) << QString("format type not set, want %1 got %2")
                       .arg(snd_pcm_format_name((snd_pcm_format_t)format))
                       .arg(snd_pcm_format_name((snd_pcm_format_t)vval));
            format = (snd_pcm_format_t)vval;
        }
        qLog(QAudioInput) << QString("format = '%1' (%2)")
            .arg(snd_pcm_format_name((snd_pcm_format_t)vval))
            .arg(snd_pcm_format_description((snd_pcm_format_t)vval))
            .toLatin1().constData();

        snd_pcm_hw_params_get_subformat(hwparams,&sval);
        vval = (unsigned int)sval;
        qLog(QAudioInput) << QString("subformat = '%1' (%2)")
            .arg(snd_pcm_subformat_name((snd_pcm_subformat_t)vval))
            .arg(snd_pcm_subformat_description((snd_pcm_subformat_t)vval))
            .toLatin1().constData();

        snd_pcm_hw_params_get_channels(hwparams, &vval);
        if ( (int)vval != (int)channels ) {
            qLog(QAudioInput) << QString("channels type not set, want %1 got %2").arg(channels).arg(vval);
            channels = vval;
        }
        qLog(QAudioInput) << "channels = " << vval;

        snd_pcm_hw_params_get_rate(hwparams, &vval, &dir);
        if ( (int)vval != (int)frequency ) {
            qLog(QAudioInput) << QString("frequency type not set, want %1 got %2").arg(frequency).arg(vval);
            frequency = vval;
        }
        qLog(QAudioInput) << "rate =" <<  vval << " bps";

        snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
        qLog(QAudioInput) << "period time =" << period_time << " us";
        snd_pcm_hw_params_get_period_size(hwparams,&period_size, &dir);
        qLog(QAudioInput) << "period size =" << (int)period_size;
        snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
        qLog(QAudioInput) << "buffer time =" << buffer_time;
        snd_pcm_hw_params_get_buffer_size(hwparams,(snd_pcm_uframes_t *) &buffer_size);
        qLog(QAudioInput) << "buffer size =" << (int)buffer_size;
        snd_pcm_hw_params_get_periods(hwparams, &vval, &dir);
        qLog(QAudioInput) << "periods per buffer =" << vval;
        snd_pcm_hw_params_get_rate_numden(hwparams, &vval, &vval2);
        qLog(QAudioInput) << QString("exact rate = %1/%2 bps").arg(vval).arg(vval2).toLatin1().constData();
        vval = snd_pcm_hw_params_get_sbits(hwparams);
        qLog(QAudioInput) << "significant bits =" << vval;
        snd_pcm_hw_params_get_tick_time(hwparams,&vval, &dir);
        qLog(QAudioInput) << "tick time =" << vval;
        vval = snd_pcm_hw_params_is_batch(hwparams);
        qLog(QAudioInput) << "is batch =" << vval;
        vval = snd_pcm_hw_params_is_block_transfer(hwparams);
        qLog(QAudioInput) << "is block transfer =" << vval;
        vval = snd_pcm_hw_params_is_double(hwparams);
        qLog(QAudioInput) << "is double =" << vval;
        vval = snd_pcm_hw_params_is_half_duplex(hwparams);
        qLog(QAudioInput) << "is half duplex =" << vval;
        vval = snd_pcm_hw_params_is_joint_duplex(hwparams);
        qLog(QAudioInput) << "is joint duplex =" << vval;
        vval = snd_pcm_hw_params_can_overrange(hwparams);
        qLog(QAudioInput) << "can overrange =" << vval;
        vval = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams);
        qLog(QAudioInput) << "can mmap =" << vval;
        vval = snd_pcm_hw_params_can_pause(hwparams);
        qLog(QAudioInput) << "can pause =" << vval;
        vval = snd_pcm_hw_params_can_resume(hwparams);
        qLog(QAudioInput) << "can resume =" << vval;
        vval = snd_pcm_hw_params_can_sync_start(hwparams);
        qLog(QAudioInput) << "can sync start =" << vval;

        snd_pcm_sw_params_t *swparams;
        snd_pcm_sw_params_alloca(&swparams);
        err = snd_pcm_sw_params_current(handle, swparams);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params_current: err %d",err);
        }
        err = snd_pcm_sw_params_set_start_threshold(handle,swparams,period_size);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params_set_start_threshold: err %d",err);
        }
        err = snd_pcm_sw_params_set_avail_min(handle, swparams,period_size);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params_set_avail_min: err %d",err);
        }
        err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params_set_xfer_align: err %d",err);
        }
        err = snd_pcm_sw_params(handle, swparams);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params: err %d",err);
        }

        snd_pcm_prepare(handle);
        snd_pcm_start(handle);

        int     count = snd_pcm_poll_descriptors_count(handle);
        pollfd  *pfds = new pollfd[count];

        snd_pcm_poll_descriptors(handle, pfds, count);

        for (int i = 0; i < count; ++i)
        {
            if ((pfds[i].events & POLLIN) != 0) {
                notifier = new QSocketNotifier(pfds[i].fd, QSocketNotifier::Read);
                QObject::connect(notifier,
                                 SIGNAL(activated(int)),
                                 input,
                                 SIGNAL(readyRead()));

                break;
            }
        }

        if (notifier == NULL) {
            rc = false;
        }

        delete pfds;
    }

    return rc;
}
Esempio n. 17
0
static int sndo_pcm_initialize(sndo_pcm_t *pcm)
{
	int err;
	snd_pcm_uframes_t boundary;
	snd_pcm_uframes_t p_period_size = ~0UL, c_period_size = ~0UL;
	snd_pcm_uframes_t p_buffer_size = ~0UL, c_buffer_size = ~0UL;

	if (pcm->playback) {
		err = snd_pcm_hw_params(pcm->playback, pcm->p_hw_params);
		if (err < 0)
			return err;
		err = snd_pcm_hw_params_get_period_size(pcm->p_hw_params, &p_period_size, NULL);
		if (err < 0)
			return err;
		err = snd_pcm_hw_params_get_buffer_size(pcm->p_hw_params, &p_buffer_size);
		if (err < 0)
			return err;
	}
	if (pcm->capture) {
		err = snd_pcm_hw_params(pcm->capture, pcm->c_hw_params);
		if (err < 0)
			return err;
		err = snd_pcm_hw_params_get_period_size(pcm->c_hw_params, &c_period_size, NULL);
		if (err < 0)
			return err;
		err = snd_pcm_hw_params_get_buffer_size(pcm->c_hw_params, &c_buffer_size);
		if (err < 0)
			return err;
	}
	if (p_period_size < c_period_size)
		pcm->transfer_block = p_period_size;
	else
		pcm->transfer_block = c_period_size;
	if (p_buffer_size < c_buffer_size)
		pcm->ring_size = p_buffer_size;
	else
		pcm->ring_size = c_buffer_size;
	if (pcm->playback) {
		err = snd_pcm_sw_params_get_boundary(pcm->p_sw_params, &boundary);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_start_threshold(pcm->playback, pcm->p_sw_params, boundary);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_stop_threshold(pcm->playback, pcm->p_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_xfer_align(pcm->playback, pcm->p_sw_params, 1);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_avail_min(pcm->playback, pcm->p_sw_params, pcm->transfer_block);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params(pcm->playback, pcm->p_sw_params);
		if (err < 0)
			return err;
	}
	if (pcm->capture) {
		err = snd_pcm_sw_params_get_boundary(pcm->c_sw_params, &boundary);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_start_threshold(pcm->capture, pcm->c_sw_params, boundary);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_stop_threshold(pcm->capture, pcm->c_sw_params, pcm->xrun == SNDO_PCM_XRUN_IGNORE ? boundary : pcm->ring_size);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_xfer_align(pcm->capture, pcm->c_sw_params, 1);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params_set_avail_min(pcm->capture, pcm->c_sw_params, pcm->transfer_block);
		if (err < 0)
			return err;
		err = snd_pcm_sw_params(pcm->capture, pcm->c_sw_params);
		if (err < 0)
			return err;
	}
	pcm->initialized = 1;
	return 0;
}
Esempio n. 18
0
static int
set_swparams (GstAlsaSink * alsa)
{
    int err;
    snd_pcm_sw_params_t *params;

    snd_pcm_sw_params_malloc (&params);

    /* get the current swparams */
    CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config);
    /* start the transfer when the buffer is almost full: */
    /* (buffer_size / avail_min) * avail_min */
    CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params,
            (alsa->buffer_size / alsa->period_size) * alsa->period_size),
           start_threshold);

    /* allow the transfer when at least period_size samples can be processed */
    CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params,
                                            alsa->period_size), set_avail);

#if GST_CHECK_ALSA_VERSION(1,0,16)
    /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */
#else
    /* align all transfers to 1 sample */
    CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align);
#endif

    /* write the parameters to the playback device */
    CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);

    snd_pcm_sw_params_free (params);
    return 0;

    /* ERRORS */
no_config:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
                           ("Unable to determine current swparams for playback: %s",
                            snd_strerror (err)));
        snd_pcm_sw_params_free (params);
        return err;
    }
start_threshold:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
                           ("Unable to set start threshold mode for playback: %s",
                            snd_strerror (err)));
        snd_pcm_sw_params_free (params);
        return err;
    }
set_avail:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
                           ("Unable to set avail min for playback: %s", snd_strerror (err)));
        snd_pcm_sw_params_free (params);
        return err;
    }
#if !GST_CHECK_ALSA_VERSION(1,0,16)
set_align:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
                           ("Unable to set transfer align for playback: %s", snd_strerror (err)));
        snd_pcm_sw_params_free (params);
        return err;
    }
#endif
set_sw_params:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
                           ("Unable to set sw params for playback: %s", snd_strerror (err)));
        snd_pcm_sw_params_free (params);
        return err;
    }
}
Esempio n. 19
0
static int
pcmout_alsa_init(sfx_pcm_device_t *self)
{
	unsigned int rrate;
	int err, dir;
	snd_pcm_hw_params_t *hwparams;
	snd_pcm_sw_params_t *swparams;
	pthread_attr_t attr;

	snd_pcm_hw_params_alloca(&hwparams);
	snd_pcm_sw_params_alloca(&swparams);

	err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0);
	if (err < 0) {
		sciprintf("[SND:ALSA] Playback open error: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params_any(handle, hwparams);
	if (err < 0) {
		sciprintf("[SND:ALSA] Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
	if (err < 0) {
		sciprintf("[SND:ALSA] Access type not available for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params_set_format(handle, hwparams, format);
	if (err < 0) {
		sciprintf("[SND:ALSA] Sample format not available for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params_set_channels(handle, hwparams, channels);
	if (err < 0) {
		sciprintf("[SND:ALSA] Channels count (%i) not available for playback: %s\n", channels, snd_strerror(err));
		return SFX_ERROR;
	}
	rrate = rate;
	err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rrate, 0);
	if (err < 0) {
		sciprintf("[SND:ALSA] Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
		return SFX_ERROR;
	}
	if (rrate != rate) {
		sciprintf("[SND:ALSA] Rate doesn't match (requested %iHz, get %iHz)\n", rate, err);
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to set buffer time %i for playback: %s\n", buffer_time, snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params_get_buffer_size(hwparams, (snd_pcm_uframes_t*)&buffer_size);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to get buffer size for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to set period time %i for playback: %s\n", period_time, snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params_get_period_size(hwparams, (snd_pcm_uframes_t*)&period_size, &dir);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to get period size for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	if (period_size >= buffer_size) {
		sciprintf("[SND:ALSA] Period size %i matches or exceeds buffer size %i\n", period_size, buffer_size);
		return SFX_ERROR;
	}
	err = snd_pcm_hw_params(handle, hwparams);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to set hw params for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_sw_params_current(handle, swparams);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to determine current swparams for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, buffer_size);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to set start threshold mode for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to set avail min for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to set transfer align for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}
	err = snd_pcm_sw_params(handle, swparams);
	if (err < 0) {
		sciprintf("[SND:ALSA] Unable to set sw params for playback: %s\n", snd_strerror(err));
		return SFX_ERROR;
	}

	self->buf_size = buffer_size;
	self->conf.rate = rate;
	self->conf.stereo = channels > 1;
	self->conf.format = SFX_PCM_FORMAT_S16_NATIVE;

	frame_size = SFX_PCM_FRAME_SIZE(self->conf);

	sfx_audbuf_init(&audio_buffer, self->conf);

	if (pthread_mutex_init(&mutex, NULL) != 0) {
		sciprintf("[SND:ALSA] Failed to create mutex\n");
		return SFX_ERROR;
	}

	run_thread = 1;
	if (pthread_create(&thread, NULL, alsa_thread, self) != 0) {
		sciprintf("[SND:ALSA] Failed to create thread\n");
		return SFX_ERROR;
	}

	return SFX_OK;
}
Esempio n. 20
0
static int initialize_device(struct audio_info_struct *ai)
{
    snd_pcm_hw_params_t *hw;
    int i;
    snd_pcm_format_t format;
    unsigned int rate;
    snd_pcm_uframes_t buffer_size;
    snd_pcm_uframes_t period_size;
    snd_pcm_sw_params_t *sw;
    snd_pcm_uframes_t boundary;

    snd_pcm_hw_params_alloca(&hw);
    if (snd_pcm_hw_params_any(ai->handle, hw) < 0) {
        fprintf(stderr, "initialize_device(): no configuration available\n");
        return -1;
    }
    if (snd_pcm_hw_params_set_access(ai->handle, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
        fprintf(stderr, "initialize_device(): device does not support interleaved access\n");
        return -1;
    }
    format = SND_PCM_FORMAT_UNKNOWN;
    for (i = 0; i < NUM_FORMATS; ++i) {
        if (ai->format == format_map[i].mpg123) {
            format = format_map[i].alsa;
            break;
        }
    }
    if (format == SND_PCM_FORMAT_UNKNOWN) {
        fprintf(stderr, "initialize_device(): invalid sample format %d\n", ai->format);
        errno = EINVAL;
        return -1;
    }
    if (snd_pcm_hw_params_set_format(ai->handle, hw, format) < 0) {
        fprintf(stderr, "initialize_device(): cannot set format %s\n", snd_pcm_format_name(format));
        return -1;
    }
    if (snd_pcm_hw_params_set_channels(ai->handle, hw, ai->channels) < 0) {
        fprintf(stderr, "initialize_device(): cannot set %d channels\n", ai->channels);
        return -1;
    }
    rate = ai->rate;
    if (snd_pcm_hw_params_set_rate_near(ai->handle, hw, &rate, NULL) < 0) {
        fprintf(stderr, "initialize_device(): cannot set rate %u\n", rate);
        return -1;
    }
    if (!rates_match(ai->rate, rate)) {
        fprintf(stderr, "initialize_device(): rate %ld not available, using %u\n", ai->rate, rate);
        /* return -1; */
    }
    buffer_size = rate * BUFFER_LENGTH;
    if (snd_pcm_hw_params_set_buffer_size_near(ai->handle, hw, &buffer_size) < 0) {
        fprintf(stderr, "initialize_device(): cannot set buffer size\n");
        return -1;
    }
    period_size = buffer_size / 4;
    if (snd_pcm_hw_params_set_period_size_near(ai->handle, hw, &period_size, NULL) < 0) {
        fprintf(stderr, "initialize_device(): cannot set period size\n");
        return -1;
    }
    if (snd_pcm_hw_params(ai->handle, hw) < 0) {
        fprintf(stderr, "initialize_device(): cannot set hw params\n");
        return -1;
    }

    snd_pcm_sw_params_alloca(&sw);
    if (snd_pcm_sw_params_current(ai->handle, sw) < 0) {
        fprintf(stderr, "initialize_device(): cannot get sw params\n");
        return -1;
    }
    /* start playing after the first write */
    if (snd_pcm_sw_params_set_start_threshold(ai->handle, sw, 1) < 0) {
        fprintf(stderr, "initialize_device(): cannot set start threshold\n");
        return -1;
    }
    if (snd_pcm_sw_params_get_boundary(sw, &boundary) < 0) {
        fprintf(stderr, "initialize_device(): cannot get boundary\n");
        return -1;
    }
    /* never stop on underruns */
    if (snd_pcm_sw_params_set_stop_threshold(ai->handle, sw, boundary) < 0) {
        fprintf(stderr, "initialize_device(): cannot set stop threshold\n");
        return -1;
    }
    /* wake up on every interrupt */
    if (snd_pcm_sw_params_set_avail_min(ai->handle, sw, 1) < 0) {
        fprintf(stderr, "initialize_device(): cannot set min avail\n");
        return -1;
    }
#if 0
    /* always write as many frames as possible */
    if (snd_pcm_sw_params_set_xfer_align(ai->handle, sw, 1) < 0) {
        fprintf(stderr, "initialize_device(): cannot set transfer alignment\n");
        return -1;
    }
#endif
    /* play silence when there is an underrun */
    if (snd_pcm_sw_params_set_silence_size(ai->handle, sw, boundary) < 0) {
        fprintf(stderr, "initialize_device(): cannot set silence size\n");
        return -1;
    }
    if (snd_pcm_sw_params(ai->handle, sw) < 0) {
        fprintf(stderr, "initialize_device(): cannot set sw params\n");
        return -1;
    }
    return 0;
}
Esempio n. 21
0
adv_error soundb_alsa_init(int sound_id, unsigned* rate, adv_bool stereo_flag, double buffer_time)
{
	int r;
	snd_pcm_hw_params_t* hw_params;
	snd_pcm_sw_params_t* sw_params;
	snd_pcm_uframes_t buffer_size;

	log_std(("sound:alsa: soundb_alsa_init(id:%d, rate:%d, stereo:%d, buffer_time:%g)\n", sound_id, *rate, stereo_flag, buffer_time));

	if (!alsa_option.initialized) {
		soundb_alsa_default();
	}

	alsa_state.volume = ALSA_VOLUME_BASE;

	if (stereo_flag) {
		alsa_state.sample_length = 4;
		alsa_state.channel = 2;
	} else {
		alsa_state.sample_length = 2;
		alsa_state.channel = 1;
	}

	log_std(("sound:alsa: using device %s\n", alsa_option.device_buffer));

	r = snd_pcm_open(&alsa_state.handle, alsa_option.device_buffer, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't open audio device %s: %s\n", alsa_option.device_buffer, snd_strerror(r)));
		goto err;
	}

	snd_pcm_hw_params_alloca(&hw_params);
	snd_pcm_sw_params_alloca(&sw_params);

	r = snd_pcm_hw_params_any(alsa_state.handle, hw_params);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't get hardware config: %s\n", snd_strerror(r)));
		goto err_close;
	}

	r = snd_pcm_hw_params_set_access(alsa_state.handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't set interleaved access: %s\n", snd_strerror(r)));
		goto err_close;
	}

	r = snd_pcm_hw_params_set_format(alsa_state.handle, hw_params, SND_PCM_FORMAT_S16_LE);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't set audio format: %s\n", snd_strerror(r)));
		goto err_close;
	}

	r = snd_pcm_hw_params_set_channels(alsa_state.handle, hw_params, alsa_state.channel);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't set audio channels: %s\n", snd_strerror(r)));
		goto err_close;
	}

	alsa_state.rate = *rate;
	r = snd_pcm_hw_params_set_rate_near(alsa_state.handle, hw_params, &alsa_state.rate, 0);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't set audio frequency: %s\n", snd_strerror(r)));
		goto err_close;
	}
	log_std(("sound:alsa: selected rate %d\n", alsa_state.rate));

	buffer_size = alsa_state.rate * buffer_time;

	log_std(("sound:alsa: request buffer_size of %d samples\n", (unsigned)buffer_size));

	r = snd_pcm_hw_params_set_buffer_size_min(alsa_state.handle, hw_params, &buffer_size);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't set buffer size min %d: %s\n", (unsigned)buffer_size, snd_strerror(r)));
		r = snd_pcm_hw_params_set_buffer_size_near(alsa_state.handle, hw_params, &buffer_size);
		if (r < 0) {
			log_std(("ERROR:sound:alsa: Couldn't set buffer size near %d: %s\n", (unsigned)buffer_size, snd_strerror(r)));
			goto err_close;
		} else {
			log_std(("sound:alsa: set_buffer_size_near() -> %d\n", (unsigned)buffer_size));
		}
	} else {
		log_std(("sound:alsa: set_buffer_size_min() -> %d\n", (unsigned)buffer_size));
	}

	if (buffer_size < alsa_state.rate * buffer_time) {
		log_std(("ERROR:sound:alsa: audio buffer TOO SMALL\n"));
	}

	r = snd_pcm_hw_params(alsa_state.handle, hw_params);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't set hw audio parameters: %s\n", snd_strerror(r)));
		goto err_close;
	}

	r = snd_pcm_sw_params_current(alsa_state.handle, sw_params);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't get software audio parameters: %s\n", snd_strerror(r)));
		goto err_close;
	}

	r = snd_pcm_sw_params_set_xfer_align(alsa_state.handle, sw_params, 1);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't set xfer_align: %s\n", snd_strerror(r)));
		goto err_close;
	}

	r = snd_pcm_sw_params(alsa_state.handle, sw_params);
	if (r < 0) {
		log_std(("ERROR:sound:alsa: Couldn't set sw audio parameters: %s\n", snd_strerror(r)));
		goto err_close;
	}

	alsa_log(hw_params, sw_params);

	*rate = alsa_state.rate;

	return 0;

err_close:
	snd_pcm_close(alsa_state.handle);
err:
	error_set("Error initializing the ALSA library.\n");
	return -1;
}
Esempio n. 22
0
static int initialize_device(audio_output_t *ao)
{
	snd_pcm_hw_params_t *hw=NULL;
	snd_pcm_sw_params_t *sw=NULL;
	snd_pcm_uframes_t buffer_size;
	snd_pcm_uframes_t period_size;
	snd_pcm_format_t format;
	snd_pcm_t *pcm=(snd_pcm_t*)ao->userptr;
	unsigned int rate;
	int i;

	snd_pcm_hw_params_alloca(&hw); /* Ignore GCC warning here... alsa-lib>=1.0.16 doesn't trigger that anymore, too. */
	if (snd_pcm_hw_params_any(pcm, hw) < 0) {
		if(!0) printf("initialize_device(): no configuration available");
		return -1;
	}
	if (snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
		if(!0) printf("initialize_device(): device does not support interleaved access");
		return -1;
	}

#if 0
	format = SND_PCM_FORMAT_UNKNOWN;
	for (i = 0; i < NUM_FORMATS; ++i) {
		if (ao->format == format_map[i].mpg123) {
			format = format_map[i].alsa;
			break;
		}
	}
	if (format == SND_PCM_FORMAT_UNKNOWN) {
		if(!0) printf("initialize_device(): invalid sample format %d", ao->format);
		errno = EINVAL;
		return -1;
	}
#endif
    format = SND_PCM_FORMAT_S16_LE;
	if (snd_pcm_hw_params_set_format(pcm, hw, format) < 0) {
		if(!0) printf("initialize_device(): cannot set format %s", snd_pcm_format_name(format));
		return -1;
	}
	if (snd_pcm_hw_params_set_channels(pcm, hw, ao->channels) < 0) {
		if(!0) printf("initialize_device(): cannot set %d channels", ao->channels);
		return -1;
	}
	rate = ao->rate;
	if (snd_pcm_hw_params_set_rate_near(pcm, hw, &rate, NULL) < 0) {
		if(!0) printf("initialize_device(): cannot set rate %u", rate);
		return -1;
	}
	if (!rates_match(ao->rate, rate)) {
		if(!0) error2("initialize_device(): rate %ld not available, using %u", ao->rate, rate);
		/* return -1; */
	}
	buffer_size = rate * BUFFER_LENGTH;
	if (snd_pcm_hw_params_set_buffer_size_near(pcm, hw, &buffer_size) < 0) {
		if(!0) printf("initialize_device(): cannot set buffer size");
		return -1;
	}
	printf("buffer_size=%lu", (unsigned long)buffer_size);
	period_size = buffer_size / 4;
	if (snd_pcm_hw_params_set_period_size_near(pcm, hw, &period_size, NULL) < 0) {
		if(!0) printf("initialize_device(): cannot set period size");
		return -1;
	}
	if (snd_pcm_hw_params(pcm, hw) < 0) {
		if(!0) printf("initialize_device(): cannot set hw params");
		return -1;
	}

	snd_pcm_sw_params_alloca(&sw);
	if (snd_pcm_sw_params_current(pcm, sw) < 0) {
		if(!0) printf("initialize_device(): cannot get sw params");
		return -1;
	}
	/* start playing right away */
	if (snd_pcm_sw_params_set_start_threshold(pcm, sw, 1) < 0) {
		if(!0) printf("initialize_device(): cannot set start threshold");
		return -1;
	}
	/* wake up on every interrupt */
	if (snd_pcm_sw_params_set_avail_min(pcm, sw, 1) < 0) {
		if(!0) printf("initialize_device(): cannot set min available");
		return -1;
	}
#if SND_LIB_VERSION < ((1<<16)|16)
	/* Always write as many frames as possible (deprecated since alsa-lib 1.0.16) */
	if (snd_pcm_sw_params_set_xfer_align(pcm, sw, 1) < 0) {
		if(!0) printf("initialize_device(): cannot set transfer alignment");
		return -1;
	}
#endif
	if (snd_pcm_sw_params(pcm, sw) < 0) {
		if(!0) printf("initialize_device(): cannot set sw params");
		return -1;
	}
	return 0;
}