Exemplo n.º 1
0
static boolean audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_handle)
{
	int error;
	snd_pcm_hw_params_t* hw_params;

	if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0)
	{
		DEBUG_WARN("snd_pcm_hw_params_malloc (%s)",
			 snd_strerror(error));
		return False;
	}
	snd_pcm_hw_params_any(capture_handle, hw_params);
	snd_pcm_hw_params_set_access(capture_handle, hw_params,
		SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(capture_handle, hw_params,
		alsa->format);
	snd_pcm_hw_params_set_rate_near(capture_handle, hw_params,
		&alsa->actual_rate, NULL);
	snd_pcm_hw_params_set_channels_near(capture_handle, hw_params,
		&alsa->actual_channels);
	snd_pcm_hw_params(capture_handle, hw_params);
	snd_pcm_hw_params_free(hw_params);
	snd_pcm_prepare(capture_handle);

	if ((alsa->actual_rate != alsa->target_rate) ||
		(alsa->actual_channels != alsa->target_channels))
	{
		DEBUG_DVC("actual rate %d / channel %d is "
			"different from target rate %d / channel %d, resampling required.",
			alsa->actual_rate, alsa->actual_channels,
			alsa->target_rate, alsa->target_channels);
	}
	return True;
}
Exemplo n.º 2
0
TErrors SalsaStream::setChannelCount(TChannels channels) {
	if(pcm_state_ != CLOSED) refreshState();
	if(pcm_state_ == OPENED || pcm_state_ == SETUP) {

		snd_pcm_hw_params_alloca(&hw_config_);
		snd_pcm_hw_params_current(pcm_, hw_config_);

		unsigned int ch = channels;
		int err = snd_pcm_hw_params_set_channels_near(pcm_, hw_config_, &ch);
		CHECK_SNDERROR(err, E_STREAM_CONFIG);

		channels_ = (TChannels) ch;
		if(channels != ch){
			stringstream s;
			const char* dir = (direction_==INPUT_STREAM)?"Input":"Output";
			s << dir<< " stream: "<<
					name_ << "channel number: given = " << channels <<
					"applied = " << ch;
			LOGGER().warning(E_STREAM_PARAM_DIFFERENCE, s.str().c_str());
			return E_STREAM_PARAM_DIFFERENCE;
		}


		snd_pcm_hw_params(pcm_, hw_config_);
	}
	else channels_ = channels;

	return E_OK;
}
Exemplo n.º 3
0
static BOOL tsmf_alsa_set_format(ITSMFAudioDevice *audio,
								 UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
{
	int error;
	snd_pcm_uframes_t frames;
	snd_pcm_hw_params_t *hw_params;
	snd_pcm_sw_params_t *sw_params;
	TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
	if(!alsa->out_handle)
		return FALSE;
	snd_pcm_drop(alsa->out_handle);
	alsa->actual_rate = alsa->source_rate = sample_rate;
	alsa->actual_channels = alsa->source_channels = channels;
	alsa->bytes_per_sample = bits_per_sample / 8;
	error = snd_pcm_hw_params_malloc(&hw_params);
	if(error < 0)
	{
		WLog_ERR(TAG, "snd_pcm_hw_params_malloc failed");
		return FALSE;
	}
	snd_pcm_hw_params_any(alsa->out_handle, hw_params);
	snd_pcm_hw_params_set_access(alsa->out_handle, hw_params,
								 SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(alsa->out_handle, hw_params,
								 SND_PCM_FORMAT_S16_LE);
	snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params,
									&alsa->actual_rate, NULL);
	snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params,
										&alsa->actual_channels);
	frames = sample_rate;
	snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params,
										   &frames);
	snd_pcm_hw_params(alsa->out_handle, hw_params);
	snd_pcm_hw_params_free(hw_params);
	error = snd_pcm_sw_params_malloc(&sw_params);
	if(error < 0)
	{
		WLog_ERR(TAG, "snd_pcm_sw_params_malloc");
		return FALSE;
	}
	snd_pcm_sw_params_current(alsa->out_handle, sw_params);
	snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params,
										  frames / 2);
	snd_pcm_sw_params(alsa->out_handle, sw_params);
	snd_pcm_sw_params_free(sw_params);
	snd_pcm_prepare(alsa->out_handle);
	DEBUG_TSMF("sample_rate %d channels %d bits_per_sample %d",
			   sample_rate, channels, bits_per_sample);
	DEBUG_TSMF("hardware buffer %d frames", (int)frames);
	if((alsa->actual_rate != alsa->source_rate) ||
			(alsa->actual_channels != alsa->source_channels))
	{
		DEBUG_TSMF("actual rate %d / channel %d is different "
				   "from source rate %d / channel %d, resampling required.",
				   alsa->actual_rate, alsa->actual_channels,
				   alsa->source_rate, alsa->source_channels);
	}
	return TRUE;
}
Exemplo n.º 4
0
static int
set_params(struct alsa_device_data * alsa_data)
{
	snd_pcm_hw_params_t * hw_params;
	snd_pcm_sw_params_t * sw_params;
	int error;
	snd_pcm_uframes_t frames;

	snd_pcm_drop(alsa_data->out_handle);

	error = snd_pcm_hw_params_malloc(&hw_params);
	if (error < 0)
	{
		LLOGLN(0, ("set_params: snd_pcm_hw_params_malloc failed"));
		return 1;
	}
	snd_pcm_hw_params_any(alsa_data->out_handle, hw_params);
	snd_pcm_hw_params_set_access(alsa_data->out_handle, hw_params,
		SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(alsa_data->out_handle, hw_params,
		alsa_data->format);
	snd_pcm_hw_params_set_rate_near(alsa_data->out_handle, hw_params,
		&alsa_data->actual_rate, NULL);
	snd_pcm_hw_params_set_channels_near(alsa_data->out_handle, hw_params,
		&alsa_data->actual_channels);
	frames = alsa_data->actual_rate * 4;
	snd_pcm_hw_params_set_buffer_size_near(alsa_data->out_handle, hw_params,
		&frames);
	snd_pcm_hw_params(alsa_data->out_handle, hw_params);
	snd_pcm_hw_params_free(hw_params);

	error = snd_pcm_sw_params_malloc(&sw_params);
	if (error < 0)
	{
		LLOGLN(0, ("set_params: snd_pcm_sw_params_malloc"));
		return 1;
	}
	snd_pcm_sw_params_current(alsa_data->out_handle, sw_params);
	snd_pcm_sw_params_set_start_threshold(alsa_data->out_handle, sw_params,
		frames / 2);
	snd_pcm_sw_params(alsa_data->out_handle, sw_params);
	snd_pcm_sw_params_free(sw_params);

	snd_pcm_prepare(alsa_data->out_handle);

	LLOGLN(10, ("set_params: hardware buffer %d frames, playback buffer %.2g seconds",
		(int)frames, (double)frames / 2.0 / (double)alsa_data->actual_rate));
	if ((alsa_data->actual_rate != alsa_data->source_rate) ||
		(alsa_data->actual_channels != alsa_data->source_channels))
	{
		LLOGLN(0, ("set_params: actual rate %d / channel %d is different from source rate %d / channel %d, resampling required.",
			alsa_data->actual_rate, alsa_data->actual_channels, alsa_data->source_rate, alsa_data->source_channels));
	}
	return 0;
}
Exemplo n.º 5
0
TErrors SalsaStream::_open(int mode) {
	if( pcm_state_ != CLOSED ) return E_OK;

		char cname[10];
		sprintf(cname, "hw:%d,%d", card_number_, device_number_);
		int err;
		err = snd_pcm_open(&pcm_, cname, direction_, mode);
		CHECK_SNDERROR(err, E_OPEN_STREAM);

		//snd_pcm_sw_params_current(pcm_, sw_config_);

		snd_pcm_hw_params_alloca(&hw_config_);
		snd_pcm_hw_params_any(pcm_, hw_config_);

		unsigned int temp = rate_;
		err = snd_pcm_hw_params_set_rate_near(pcm_, hw_config_, &temp, NULL);
		CHECK_SNDERROR(err, E_STREAM_CONFIG);

		if( temp != rate_) {
			// cannot set the rate to the specified but to the nearest
			LOGGER().warning(E_STREAM_CONFIG,
					"Cannot set sampling rate to the specified value");
			rate_ = temp;

		}

		temp = channels_;
		err = snd_pcm_hw_params_set_channels_near(pcm_, hw_config_, &temp);
		CHECK_SNDERROR(err, E_STREAM_CONFIG);
		if( temp != channels_) {
			// channels set  to the nearest possible to given
			channels_ = (TChannels)temp;
			LOGGER().warning(E_STREAM_CONFIG,
							"Cannot set channel count to the specified value");

		}
		snd_pcm_hw_params(pcm_, hw_config_);
		/* allocate software parameters */
	//	err = snd_pcm_sw_params_malloc(&sw_config_);
	//	CHECK_SNDERROR(err, E_STREAM_CONFIG);
	//	err = snd_pcm_sw_params_current(pcm_, sw_config_);
	//	CHECK_SNDERROR(err, E_STREAM_CONFIG);
	//	err = snd_pcm_sw_params_set_start_threshold (pcm_, sw_config_, 0U );
	//	CHECK_SNDERROR(err, E_STREAM_CONFIG);
	//	err = snd_pcm_sw_params_set_avail_min(pcm_, sw_config_, buffer_size_/2);
	//	CHECK_SNDERROR(err, E_STREAM_CONFIG);
	//	snd_pcm_sw_params(pcm_, sw_config_);

		pcm_state_ = OPENED;

		return E_OK;
}
Exemplo n.º 6
0
static int init(struct xmp_context *ctx)
{
	snd_pcm_hw_params_t *hwparams;
	int ret;
	char *token, **parm;
	unsigned int channels, rate;
	unsigned int btime = 2000000;	/* 2s */
	unsigned int ptime = 100000;	/* 100ms */
	char *card_name = "default";
	struct xmp_options *o = &ctx->o;

	parm_init();  
	chkparm1("buffer", btime = 1000 * strtoul(token, NULL, 0));
	chkparm1("period", btime = 1000 * strtoul(token, NULL, 0));
	chkparm1("card", card_name = token);
	parm_end();

	if ((ret = snd_pcm_open(&pcm_handle, card_name,
		SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
		fprintf(stderr, "Unable to initialize ALSA pcm device: %s\n",
					snd_strerror(ret));
		return XMP_ERR_DINIT;
	}

	channels = (o->outfmt & XMP_FMT_MONO) ? 1 : 2;
	rate = o->freq;

	snd_pcm_hw_params_alloca(&hwparams);
	snd_pcm_hw_params_any(pcm_handle, hwparams);
	snd_pcm_hw_params_set_access(pcm_handle, hwparams,
		SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(pcm_handle, hwparams, to_fmt(o));
	snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &rate, 0);
	snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &channels);
	snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &btime, 0);
	snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &ptime, 0);
	snd_pcm_nonblock(pcm_handle, 0);
	
	if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
		fprintf(stderr, "Unable to set ALSA output parameters: %s\n",
					snd_strerror(ret));
		return XMP_ERR_DINIT;
	}

	if (prepare_driver() < 0)
		return XMP_ERR_DINIT;
  
	o->freq = rate;

	return xmp_smix_on(ctx);
}
    optional<int> AudioOutputDeviceAlsa::ParameterChannels::DefaultAsInt(std::map<String,String> Parameters) {
        if (!Parameters.count("CARD")) return optional<int>::nothing;

        // obtain information from given sound card
        ParameterCard card(Parameters["CARD"]);
        String pcm_name = "hw:" + card.ValueAsString();
        snd_pcm_t* pcm_handle = NULL;
        if (snd_pcm_open(&pcm_handle, pcm_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) return optional<int>::nothing;
        snd_pcm_hw_params_t* hwparams;
        snd_pcm_hw_params_alloca(&hwparams);
        if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {
            snd_pcm_close(pcm_handle);
            return optional<int>::nothing;
        }
        uint channels = 2;
        if (snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &channels) < 0) {
            snd_pcm_close(pcm_handle);
            return optional<int>::nothing;
        }
        snd_pcm_close(pcm_handle);
        return channels;
    }
Exemplo n.º 8
0
static GF_Err ALSA_QueryOutputSampleRate(GF_AudioOutput*dr, u32 *desired_sr, u32 *NbChannels, u32 *nbBitsPerSample)
{
	ALSAContext *ctx = (ALSAContext*)dr->opaque;
	int err;
	snd_pcm_hw_params_t *hw_params = NULL;

	err = snd_pcm_hw_params_malloc(&hw_params);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot allocate hardware params: %s\n", snd_strerror (err)) );
		goto err_exit;
	}
	err = snd_pcm_hw_params_any(ctx->playback_handle, hw_params);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot initialize hardware params: %s\n", snd_strerror (err)) );
		goto err_exit;
	}

	err = snd_pcm_hw_params_set_rate_near(ctx->playback_handle, hw_params, desired_sr, 0);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot check available sample rates: %s\n", snd_strerror (err)) );
		goto err_exit;
	}

	err = snd_pcm_hw_params_set_channels_near(ctx->playback_handle, hw_params, NbChannels);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot check available channels: %s\n", snd_strerror (err)) );
		goto err_exit;
	}
	snd_pcm_hw_params_free (hw_params);
	hw_params = NULL;
	return GF_OK;
err_exit:
	snd_pcm_hw_params_free (hw_params);
	hw_params = NULL;
	return GF_IO_ERR;
}
Exemplo n.º 9
0
static bool set_snd_pcm_hw_params(snd_pcm_t *snd, snd_pcm_hw_params_t *params, snd_pcm_format_t fmt, unsigned &channels, unsigned &sample_rate, unsigned &delay_us)
{
	const bool ok = !snd_pcm_hw_params_set_access(snd, params, SND_PCM_ACCESS_RW_INTERLEAVED) && !snd_pcm_hw_params_set_format(snd, params, fmt) && !snd_pcm_hw_params_set_channels_near(snd, params, &channels) && !snd_pcm_hw_params_set_rate_near(snd, params, &sample_rate, NULL);
	if (ok)
	{
		unsigned period_us = delay_us >> 2;
		return (!snd_pcm_hw_params_set_buffer_time_near(snd, params, &delay_us, NULL) && !snd_pcm_hw_params_set_period_time_near(snd, params, &period_us, NULL)) || (!snd_pcm_hw_params_set_period_time_near(snd, params, &period_us, NULL) && !snd_pcm_hw_params_set_buffer_time_near(snd, params, &delay_us, NULL));
	}
	return false;
}
Exemplo n.º 10
0
/*
    open & setup audio device
    return: 1=success 0=fail
*/
static int init(int rate_hz, int channels, int format, int flags)
{
    unsigned int alsa_buffer_time = 500000; /* 0.5 s */
    unsigned int alsa_fragcount = 16;
    int err;
    int block;
    strarg_t device;
    snd_pcm_uframes_t chunk_size;
    snd_pcm_uframes_t bufsize;
    snd_pcm_uframes_t boundary;
    const opt_t subopts[] = {
      {"block", OPT_ARG_BOOL, &block, NULL},
      {"device", OPT_ARG_STR, &device, str_maxlen},
      {NULL}
    };

    char alsa_device[ALSA_DEVICE_SIZE + 1];
    // make sure alsa_device is null-terminated even when using strncpy etc.
    memset(alsa_device, 0, ALSA_DEVICE_SIZE + 1);

    mp_msg(MSGT_AO,MSGL_V,"alsa-init: requested format: %d Hz, %d channels, %x\n", rate_hz,
	channels, format);
    alsa_handler = NULL;
#if SND_LIB_VERSION >= 0x010005
    mp_msg(MSGT_AO,MSGL_V,"alsa-init: using ALSA %s\n", snd_asoundlib_version());
#else
    mp_msg(MSGT_AO,MSGL_V,"alsa-init: compiled for ALSA-%s\n", SND_LIB_VERSION_STR);
#endif

    snd_lib_error_set_handler(alsa_error_handler);

    ao_data.samplerate = rate_hz;
    ao_data.format = format;
    ao_data.channels = channels;

    switch (format)
      {
      case AF_FORMAT_S8:
	alsa_format = SND_PCM_FORMAT_S8;
	break;
      case AF_FORMAT_U8:
	alsa_format = SND_PCM_FORMAT_U8;
	break;
      case AF_FORMAT_U16_LE:
	alsa_format = SND_PCM_FORMAT_U16_LE;
	break;
      case AF_FORMAT_U16_BE:
	alsa_format = SND_PCM_FORMAT_U16_BE;
	break;
      case AF_FORMAT_AC3_LE:
      case AF_FORMAT_S16_LE:
      case AF_FORMAT_IEC61937_LE:
	alsa_format = SND_PCM_FORMAT_S16_LE;
	break;
      case AF_FORMAT_AC3_BE:
      case AF_FORMAT_S16_BE:
      case AF_FORMAT_IEC61937_BE:
	alsa_format = SND_PCM_FORMAT_S16_BE;
	break;
      case AF_FORMAT_U32_LE:
	alsa_format = SND_PCM_FORMAT_U32_LE;
	break;
      case AF_FORMAT_U32_BE:
	alsa_format = SND_PCM_FORMAT_U32_BE;
	break;
      case AF_FORMAT_S32_LE:
	alsa_format = SND_PCM_FORMAT_S32_LE;
	break;
      case AF_FORMAT_S32_BE:
	alsa_format = SND_PCM_FORMAT_S32_BE;
	break;
      case AF_FORMAT_U24_LE:
	alsa_format = SND_PCM_FORMAT_U24_3LE;
	break;
      case AF_FORMAT_U24_BE:
	alsa_format = SND_PCM_FORMAT_U24_3BE;
	break;
      case AF_FORMAT_S24_LE:
	alsa_format = SND_PCM_FORMAT_S24_3LE;
	break;
      case AF_FORMAT_S24_BE:
	alsa_format = SND_PCM_FORMAT_S24_3BE;
	break;
      case AF_FORMAT_FLOAT_LE:
	alsa_format = SND_PCM_FORMAT_FLOAT_LE;
	break;
      case AF_FORMAT_FLOAT_BE:
	alsa_format = SND_PCM_FORMAT_FLOAT_BE;
	break;
      case AF_FORMAT_MU_LAW:
	alsa_format = SND_PCM_FORMAT_MU_LAW;
	break;
      case AF_FORMAT_A_LAW:
	alsa_format = SND_PCM_FORMAT_A_LAW;
	break;

      default:
	alsa_format = SND_PCM_FORMAT_MPEG; //? default should be -1
	break;
      }

    //subdevice parsing
    // set defaults
    block = 1;
    /* switch for spdif
     * sets opening sequence for SPDIF
     * sets also the playback and other switches 'on the fly'
     * while opening the abstract alias for the spdif subdevice
     * 'iec958'
     */
    if (AF_FORMAT_IS_IEC61937(format)) {
	device.str = "iec958";
	mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3/iec61937/iec958, %i channels\n", channels);
    }
  else
        /* in any case for multichannel playback we should select
         * appropriate device
         */
        switch (channels) {
	case 1:
	case 2:
	  device.str = "default";
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: setup for 1/2 channel(s)\n");
	  break;
	case 4:
	  if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
	    // hack - use the converter plugin
	    device.str = "plug:surround40";
	  else
	    device.str = "surround40";
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround40\n");
	  break;
	case 6:
	  if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
	    device.str = "plug:surround51";
	  else
	    device.str = "surround51";
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround51\n");
	  break;
	case 8:
	  if (alsa_format == SND_PCM_FORMAT_FLOAT_LE)
	    device.str = "plug:surround71";
	  else
	    device.str = "surround71";
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: device set to surround71\n");
	  break;
	default:
	  device.str = "default";
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ChannelsNotSupported,channels);
        }
    device.len = strlen(device.str);
    if (subopt_parse(ao_subdevice, subopts) != 0) {
        print_help();
        return 0;
    }
    parse_device(alsa_device, device.str, device.len);

    mp_msg(MSGT_AO,MSGL_V,"alsa-init: using device %s\n", alsa_device);

    if (!alsa_handler) {
      int open_mode = block ? 0 : SND_PCM_NONBLOCK;
      int isac3 =  AF_FORMAT_IS_IEC61937(format);
      //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
      mp_msg(MSGT_AO,MSGL_V,"alsa-init: opening device in %sblocking mode\n", block ? "" : "non-");
      if ((err = try_open_device(alsa_device, open_mode, isac3)) < 0)
	{
	  if (err != -EBUSY && !block) {
	    mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed);
	    if ((err = try_open_device(alsa_device, 0, isac3)) < 0) {
	      mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
	      return 0;
	    }
	  } else {
	    mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
	    return 0;
	  }
	}

      if ((err = snd_pcm_nonblock(alsa_handler, 0)) < 0) {
         mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_ErrorSetBlockMode, snd_strerror(err));
      } else {
	mp_msg(MSGT_AO,MSGL_V,"alsa-init: device reopened in blocking mode\n");
      }

      snd_pcm_hw_params_alloca(&alsa_hwparams);
      snd_pcm_sw_params_alloca(&alsa_swparams);

      // setting hw-parameters
      if ((err = snd_pcm_hw_params_any(alsa_handler, alsa_hwparams)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetInitialParameters,
		 snd_strerror(err));
	  return 0;
	}

      err = snd_pcm_hw_params_set_access(alsa_handler, alsa_hwparams,
					 SND_PCM_ACCESS_RW_INTERLEAVED);
      if (err < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetAccessType,
	       snd_strerror(err));
	return 0;
      }

      /* workaround for nonsupported formats
	 sets default format to S16_LE if the given formats aren't supported */
      if ((err = snd_pcm_hw_params_test_format(alsa_handler, alsa_hwparams,
                                             alsa_format)) < 0)
      {
         mp_msg(MSGT_AO,MSGL_INFO,
		MSGTR_AO_ALSA_FormatNotSupportedByHardware, af_fmt2str_short(format));
         alsa_format = SND_PCM_FORMAT_S16_LE;
         if (AF_FORMAT_IS_AC3(ao_data.format))
           ao_data.format = AF_FORMAT_AC3_LE;
         else if (AF_FORMAT_IS_IEC61937(ao_data.format))
           ao_data.format = AF_FORMAT_IEC61937_LE;
         else
         ao_data.format = AF_FORMAT_S16_LE;
      }

      if ((err = snd_pcm_hw_params_set_format(alsa_handler, alsa_hwparams,
					      alsa_format)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetFormat,
		 snd_strerror(err));
	  return 0;
	}

      if ((err = snd_pcm_hw_params_set_channels_near(alsa_handler, alsa_hwparams,
						     &ao_data.channels)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetChannels,
		 snd_strerror(err));
	  return 0;
	}

      /* workaround for buggy rate plugin (should be fixed in ALSA 1.0.11)
         prefer our own resampler, since that allows users to choose the resampler,
         even per file if desired */
#if SND_LIB_VERSION >= 0x010009
      if ((err = snd_pcm_hw_params_set_rate_resample(alsa_handler, alsa_hwparams,
						     0)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToDisableResampling,
		 snd_strerror(err));
	  return 0;
	}
#endif

      if ((err = snd_pcm_hw_params_set_rate_near(alsa_handler, alsa_hwparams,
						 &ao_data.samplerate, NULL)) < 0)
        {
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSamplerate2,
		 snd_strerror(err));
	  return 0;
        }

      bytes_per_sample = af_fmt2bits(ao_data.format) / 8;
      bytes_per_sample *= ao_data.channels;
      ao_data.bps = ao_data.samplerate * bytes_per_sample;

	if ((err = snd_pcm_hw_params_set_buffer_time_near(alsa_handler, alsa_hwparams,
							  &alsa_buffer_time, NULL)) < 0)
	  {
	    mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetBufferTimeNear,
		   snd_strerror(err));
	    return 0;
	  }

	if ((err = snd_pcm_hw_params_set_periods_near(alsa_handler, alsa_hwparams,
						      &alsa_fragcount, NULL)) < 0) {
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetPeriods,
		 snd_strerror(err));
	  return 0;
	}

      /* finally install hardware parameters */
      if ((err = snd_pcm_hw_params(alsa_handler, alsa_hwparams)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetHwParameters,
		 snd_strerror(err));
	  return 0;
	}
      // end setting hw-params


      // gets buffersize for control
      if ((err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize)) < 0)
	{
	  mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBufferSize, snd_strerror(err));
	  return 0;
	}
      else {
	ao_data.buffersize = bufsize * bytes_per_sample;
	  mp_msg(MSGT_AO,MSGL_V,"alsa-init: got buffersize=%i\n", ao_data.buffersize);
      }

      if ((err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetPeriodSize, snd_strerror(err));
	return 0;
      } else {
	mp_msg(MSGT_AO,MSGL_V,"alsa-init: got period size %li\n", chunk_size);
      }
      ao_data.outburst = chunk_size * bytes_per_sample;

      /* setting software parameters */
      if ((err = snd_pcm_sw_params_current(alsa_handler, alsa_swparams)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters,
	       snd_strerror(err));
	return 0;
      }
#if SND_LIB_VERSION >= 0x000901
      if ((err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetBoundary,
	       snd_strerror(err));
	return 0;
      }
#else
      boundary = 0x7fffffff;
#endif
      /* start playing when one period has been written */
      if ((err = snd_pcm_sw_params_set_start_threshold(alsa_handler, alsa_swparams, chunk_size)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStartThreshold,
	       snd_strerror(err));
	return 0;
      }
      /* disable underrun reporting */
      if ((err = snd_pcm_sw_params_set_stop_threshold(alsa_handler, alsa_swparams, boundary)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetStopThreshold,
	       snd_strerror(err));
	return 0;
      }
#if SND_LIB_VERSION >= 0x000901
      /* play silence when there is an underrun */
      if ((err = snd_pcm_sw_params_set_silence_size(alsa_handler, alsa_swparams, boundary)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToSetSilenceSize,
	       snd_strerror(err));
	return 0;
      }
#endif
      if ((err = snd_pcm_sw_params(alsa_handler, alsa_swparams)) < 0) {
	mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_UnableToGetSwParameters,
	       snd_strerror(err));
	return 0;
      }
      /* end setting sw-params */

      mp_msg(MSGT_AO,MSGL_V,"alsa: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n",
	     ao_data.samplerate, ao_data.channels, (int)bytes_per_sample, ao_data.buffersize,
	     snd_pcm_format_description(alsa_format));

    } // end switch alsa_handler (spdif)
    alsa_can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams);
    return 1;
} // end init
Exemplo n.º 11
0
bool
ALSAPCMPlayer::SetParameters(snd_pcm_t &alsa_handle, unsigned sample_rate,
                             bool big_endian_source, unsigned latency,
                             unsigned &channels) {
  /* adoption of alsa-libs's snd_pcm_set_params() function, which is not
   * available on SALSA, with a few detail enhancements. */

  snd_pcm_hw_params_t *hw_params;
  snd_pcm_hw_params_alloca(&hw_params);

  int alsa_error = snd_pcm_hw_params_any(&alsa_handle, hw_params);
  if (alsa_error < 0) {
    LogFormat("snd_pcm_hw_params_any(0x%p, 0x%p) failed: %d - %s",
              &alsa_handle,
              hw_params,
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  /* Try to enable resampling, but do not give up if it fails. Probably we are
   * lucky and our ALSA device supports our sample rate natively. */
  snd_pcm_hw_params_set_rate_resample(&alsa_handle, hw_params, 1);

  alsa_error = snd_pcm_hw_params_set_access(&alsa_handle,
                                            hw_params,
                                            SND_PCM_ACCESS_RW_INTERLEAVED);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_hw_params_set_access(0x%p, 0x%p, "
                  "SND_PCM_ACCESS_RW_INTERLEAVED) failed: %d - %s",
              &alsa_handle,
              hw_params,
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  alsa_error = snd_pcm_hw_params_set_format(&alsa_handle,
                                            hw_params,
                                            big_endian_source
                                                ? SND_PCM_FORMAT_S16_BE
                                                : SND_PCM_FORMAT_S16_LE);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_hw_params_set_format(0x%p, 0x%p, "
                  "%s) failed: %d - %s",
              &alsa_handle,
              hw_params,
              big_endian_source
                  ? "SND_PCM_FORMAT_S16_BE"
                  : "SND_PCM_FORMAT_S16_LE",
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  assert(1 == channels);
  alsa_error = snd_pcm_hw_params_set_channels_near(&alsa_handle,
                                                   hw_params,
                                                   &channels);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_hw_params_set_channels_near(0x%p, 0x%p, 0x%p) "
                  "failed: %d - %s",
              &alsa_handle,
              hw_params,
              &channels,
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  alsa_error = snd_pcm_hw_params_set_rate(&alsa_handle,
                                          hw_params,
                                          sample_rate,
                                          0);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_hw_params_set_rate(0x%p, 0x%p, %u, 0) "
                  "failed: %d - %s",
              &alsa_handle,
              hw_params,
              sample_rate,
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  snd_pcm_uframes_t buffer_size, period_size;

  alsa_error = snd_pcm_hw_params_set_buffer_time_near(&alsa_handle,
                                                      hw_params,
                                                      &latency,
                                                      nullptr);
  if (0 != alsa_error) {
    unsigned period_time = latency / 4;
    alsa_error = snd_pcm_hw_params_set_period_time_near(&alsa_handle,
                                                        hw_params,
                                                        &period_time,
                                                        nullptr);
    if (0 != alsa_error) {
      LogFormat("snd_pcm_hw_params_set_period_time_near(0x%p, 0x%p, 0x%p, "
                    "nullptr) failed: %d - %s",
                &alsa_handle,
                hw_params,
                &period_time,
                alsa_error,
                snd_strerror(alsa_error));
      return false;
    }

    alsa_error = snd_pcm_hw_params_get_period_size(hw_params,
                                                   &period_size,
                                                   nullptr);
    if (0 != alsa_error) {
      LogFormat("snd_pcm_hw_params_get_period_size(0x%p, 0x%p, nullptr) "
                    "failed: %d - %s",
                hw_params,
                &period_size,
                alsa_error,
                snd_strerror(alsa_error));
      return false;
    }

    buffer_size = period_size * 4;
    alsa_error = snd_pcm_hw_params_set_buffer_size_near(&alsa_handle,
                                                        hw_params,
                                                        &buffer_size);
    if (0 != alsa_error) {
      LogFormat("snd_pcm_hw_params_set_buffer_size_near(0x%p, 0x%p, 0x%p) "
                    "failed: %d - %s",
                &alsa_handle,
                hw_params,
                &buffer_size,
                alsa_error,
                snd_strerror(alsa_error));
      return false;
    }

    alsa_error = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);
    if (0 != alsa_error) {
      LogFormat("snd_pcm_hw_params_get_buffer_size(0x%p, 0x%p) "
                    "failed: %d - %s",
                hw_params,
                &buffer_size,
                alsa_error,
                snd_strerror(alsa_error));
      return false;
    }
  } else {
    alsa_error = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size);
    if (0 != alsa_error) {
      LogFormat("snd_pcm_hw_params_get_buffer_size(0x%p, 0x%p) "
                    "failed: %d - %s",
                hw_params,
                &buffer_size,
                alsa_error,
                snd_strerror(alsa_error));
      return false;
    }

    alsa_error = snd_pcm_hw_params_get_buffer_time(hw_params,
                                                   &latency,
                                                   nullptr);
    if (0 != alsa_error) {
      LogFormat("snd_pcm_hw_params_get_buffer_time(0x%p, 0x%p, nullptr) "
                    "failed: %d - %s",
                hw_params,
                &latency,
                alsa_error,
                snd_strerror(alsa_error));
      return false;
    }

    unsigned period_time = latency / 4;
    alsa_error = snd_pcm_hw_params_set_period_time_near(&alsa_handle,
                                                        hw_params,
                                                        &period_time,
                                                        nullptr);
    if (0 != alsa_error) {
      LogFormat("snd_pcm_hw_params_set_period_time_near(0x%p, 0x%p, 0x%p, "
                    "nullptr) failed: %d - %s",
                &alsa_handle,
                hw_params,
                &period_time,
                alsa_error,
                snd_strerror(alsa_error));
      return false;
    }

    alsa_error = snd_pcm_hw_params_get_period_size(hw_params,
                                                   &period_size,
                                                   nullptr);
    if (0 != alsa_error) {
      LogFormat("snd_pcm_hw_params_get_period_size(0x%p, 0x%p, nullptr) "
                    "failed: %d - %s",
                hw_params,
                &period_size,
                alsa_error,
                snd_strerror(alsa_error));
      return false;
    }
  }

  alsa_error = snd_pcm_hw_params(&alsa_handle, hw_params);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_hw_params(0x%p, 0x%p) failed: %d - %s",
              &alsa_handle,
              hw_params,
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  snd_pcm_sw_params_t *sw_params;
  snd_pcm_sw_params_alloca(&sw_params);

  alsa_error = snd_pcm_sw_params_current(&alsa_handle, sw_params);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_sw_params_current(0x%p, 0x%p) failed: %d - %s",
              &alsa_handle,
              sw_params,
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  snd_pcm_uframes_t  start_threshold =
      (buffer_size / period_size) * period_size;
  alsa_error = snd_pcm_sw_params_set_start_threshold(&alsa_handle,
                                                     sw_params,
                                                     start_threshold);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_sw_params_set_start_threshold(0x%p, 0x%p, %u) "
                  "failed: %d - %s",
              &alsa_handle,
              sw_params,
              static_cast<unsigned>(start_threshold),
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  alsa_error = snd_pcm_sw_params_set_avail_min(&alsa_handle,
                                               sw_params,
                                               period_size);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_sw_params_set_avail_min(0x%p, 0x%p, %u) failed: %d - %s",
              &alsa_handle,
              sw_params,
              static_cast<unsigned>(period_size),
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  alsa_error = snd_pcm_sw_params(&alsa_handle, sw_params);
  if (0 != alsa_error) {
    LogFormat("snd_pcm_sw_params(0x%p, 0x%p) failed: %d - %s",
              &alsa_handle,
              sw_params,
              alsa_error,
              snd_strerror(alsa_error));
    return false;
  }

  return true;
}
Exemplo n.º 12
0
static GF_Err ALSA_ConfigureOutput(GF_AudioOutput*dr, u32 *SampleRate, u32 *NbChannels, u32 *nbBitsPerSample, u32 channel_cfg)
{
	snd_pcm_hw_params_t *hw_params = NULL;
	int err;
	int nb_bufs, sr, val, period_time;
	ALSAContext *ctx = (ALSAContext*)dr->opaque;

	if (!ctx) return GF_BAD_PARAM;

	/*close device*/
	if (ctx->playback_handle) {
		snd_pcm_close(ctx->playback_handle);
		ctx->playback_handle = NULL;
	}
	if (ctx->wav_buf) free(ctx->wav_buf);
	ctx->wav_buf = NULL;

	err = snd_pcm_open(&ctx->playback_handle, ctx->dev_name, SND_PCM_STREAM_PLAYBACK, 0/*SND_PCM_NONBLOCK*/);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot open audio device %s: %s\n", ctx->dev_name, snd_strerror (err)) );
		return GF_IO_ERR;
	}

	err = snd_pcm_hw_params_malloc(&hw_params);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot allocate hardware params: %s\n", snd_strerror (err)) );
		goto err_exit;
	}
	err = snd_pcm_hw_params_any(ctx->playback_handle, hw_params);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot initialize hardware params: %s\n", snd_strerror (err)) );
		goto err_exit;
	}
	err = snd_pcm_hw_params_set_access(ctx->playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set access type: %s\n", snd_strerror (err)) );
		goto err_exit;
	}
	/*set output format*/
	ctx->nb_ch = (int) (*NbChannels);
	ctx->block_align = ctx->nb_ch;
	if ((*nbBitsPerSample) == 16) {
		ctx->block_align *= 2;
		err = snd_pcm_hw_params_set_format(ctx->playback_handle, hw_params, SND_PCM_FORMAT_S16_LE);
	} else {
		err = snd_pcm_hw_params_set_format(ctx->playback_handle, hw_params, SND_PCM_FORMAT_U8);
	}
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set sample format: %s\n", snd_strerror (err)) );
		goto err_exit;
	}

	/*set output sample rate*/
	if (ctx->force_sr) *SampleRate = ctx->force_sr;
	sr = *SampleRate;
	err = snd_pcm_hw_params_set_rate_near(ctx->playback_handle, hw_params, SampleRate, 0);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set sample rate: %s\n", snd_strerror (err)) );
		goto err_exit;
	}
	if (sr != *SampleRate) {
		GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[ALSA] Sample rate %d not supported, using %d instead\n", sr, *SampleRate ) );
		sr = *SampleRate;
	}
	/*set output channels*/
	err = snd_pcm_hw_params_set_channels_near(ctx->playback_handle, hw_params, NbChannels);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set channel count: %s\n", snd_strerror (err)) );
		goto err_exit;
	}
	if (ctx->nb_ch != *NbChannels) {
		GF_LOG(GF_LOG_INFO, GF_LOG_MMIO, ("[ALSA] %d channels not supported - using %d instead\n", ctx->nb_ch, *NbChannels ) );
		ctx->block_align /= ctx->nb_ch;
		ctx->nb_ch = *NbChannels;
		ctx->block_align *= ctx->nb_ch;
	}
	err = snd_pcm_hw_params(ctx->playback_handle, hw_params);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set parameters: %s\n", snd_strerror (err)) );
		goto err_exit;
	}

	/* Set number of buffers*/
	snd_pcm_hw_params_get_periods_min(hw_params, &val, 0);
	nb_bufs = (ctx->num_buffers>val) ? ctx->num_buffers : val;
	err = snd_pcm_hw_params_set_periods_near(ctx->playback_handle, hw_params, &nb_bufs, 0);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set number of HW buffers (%d): %s\n", nb_bufs, snd_strerror(err) ));
		goto err_exit;
	}

	/* Set total buffer size*/
	if (ctx->total_duration) {
		ctx->buf_size = (sr * ctx->total_duration)/1000;
	} else {
		ctx->buf_size = 2048;
	}
	ctx->buf_size /= nb_bufs;

	err = snd_pcm_hw_params_set_period_size_near(ctx->playback_handle, hw_params, (snd_pcm_uframes_t *)&ctx->buf_size, 0);
	if (err < 0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[ALSA] Cannot set HW buffer size (%d): %s\n", ctx->buf_size, snd_strerror(err) ));
		goto err_exit;
	}
	/*get complete buffer size*/
	snd_pcm_hw_params_get_buffer_size(hw_params, (snd_pcm_uframes_t *)&ctx->buf_size);
	ctx->buf_size *= ctx->block_align;
	/*get period time*/
	snd_pcm_hw_params_get_period_time(hw_params, &period_time, 0);
	
	snd_pcm_hw_params_free (hw_params);
	hw_params = NULL;

	ctx->delay = (ctx->buf_size*1000) / (sr*ctx->block_align);

	/*allocate a single buffer*/
	ctx->wav_buf = malloc(ctx->buf_size*sizeof(char));
	if(!ctx->wav_buf) return GF_OUT_OF_MEM;
	memset(ctx->wav_buf, 0, ctx->buf_size*sizeof(char));
	GF_LOG(GF_LOG_DEBUG, GF_LOG_MMIO, ("[ALSA] Setup %d ch @ %d hz - %d periods of %d us - total buffer size %d - overall delay %d ms\n", ctx->nb_ch, sr, nb_bufs, period_time, ctx->buf_size, ctx->delay));
	
	return GF_OK;

err_exit:
	if (hw_params) snd_pcm_hw_params_free(hw_params);
	snd_pcm_close(ctx->playback_handle);
	ctx->playback_handle = NULL;
	return GF_IO_ERR;
}
Exemplo n.º 13
0
static int set_hwparams(snd_pcm_t *handle, snd_pcm_hw_params_t *params, snd_pcm_access_t access, int rate, int channels, int period, int nperiods ) {
	int err, dir=0;
	unsigned int buffer_time;
	unsigned int period_time;
	unsigned int rrate;
	unsigned int rchannels;

	/* choose all parameters */
	err = snd_pcm_hw_params_any(handle, params);
	if (err < 0) {
		printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err));
		return err;
	}
	/* set the interleaved read/write format */
	err = snd_pcm_hw_params_set_access(handle, params, access);
	if (err < 0) {
		printf("Access type not available for playback: %s\n", snd_strerror(err));
		return err;
	}

	/* set the sample format */
	err = set_hwformat(handle, params);
	if (err < 0) {
		printf("Sample format not available for playback: %s\n", snd_strerror(err));
		return err;
	}
	/* set the count of channels */
	rchannels = channels;
	err = snd_pcm_hw_params_set_channels_near(handle, params, &rchannels);
	if (err < 0) {
		printf("Channels count (%i) not available for record: %s\n", channels, snd_strerror(err));
		return err;
	}
	if (rchannels != channels) {
		printf("WARNING: chennel count does not match (requested %d got %d)\n", channels, rchannels);
		num_channels = rchannels;
	}
	/* set the stream rate */
	rrate = rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0);
	if (err < 0) {
		printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err));
		return err;
	}
	if (rrate != rate) {
		printf("Rate doesn't match (requested %iHz, get %iHz)\n", rate, rrate);
		return -EINVAL;
	}
	/* set the buffer time */

	buffer_time = 1000000*(uint64_t)period*nperiods/rate;
	err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, &dir);
	if (err < 0) {
		printf("Unable to set buffer time %i for playback: %s\n",  1000000*period*nperiods/rate, snd_strerror(err));
		return err;
	}
	err = snd_pcm_hw_params_get_buffer_size( params, &real_buffer_size );
	if (err < 0) {
		printf("Unable to get buffer size back: %s\n", snd_strerror(err));
		return err;
	}
	if( real_buffer_size != nperiods * period ) {
	    printf( "WARNING: buffer size does not match: (requested %d, got %d)\n", nperiods * period, (int) real_buffer_size );
	}
	/* set the period time */
	period_time = 1000000*(uint64_t)period/rate;
	err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, &dir);
	if (err < 0) {
		printf("Unable to set period time %i for playback: %s\n", 1000000*period/rate, snd_strerror(err));
		return err;
	}
	err = snd_pcm_hw_params_get_period_size(params, &real_period_size, NULL );
	if (err < 0) {
		printf("Unable to get period size back: %s\n", snd_strerror(err));
		return err;
	}
	if( real_period_size != period ) {
	    printf( "WARNING: period size does not match: (requested %i, got %i)\n", period, (int)real_period_size );
	}
	/* write the parameters to device */
	err = snd_pcm_hw_params(handle, params);
	if (err < 0) {
		printf("Unable to set hw params for playback: %s\n", snd_strerror(err));
		return err;
	}
	return 0;
}
Exemplo n.º 14
0
static void
init_audio(const char* devname)
{
  snd_pcm_hw_params_t* hwparams = 0;
  snd_pcm_sw_params_t* swparams = 0;
  snd_pcm_uframes_t    bufsize  = 0;
  unsigned int         buftime  = 1000000;
  unsigned int         pertime  = 50000;
  int                  dir      = 0;
  int                  rc;

  if ((rc = snd_output_stdio_attach(&output, stderr, 0)) < 0)
    exit_snd_error(rc, "log output");

  if ((rc = snd_pcm_open(&audio, devname, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
    exit_snd_error(rc, "opening device");

  if ((rc = snd_pcm_hw_params_malloc(&hwparams)) < 0)
    exit_snd_error(rc, "hardware parameters");

  if ((rc = snd_pcm_hw_params_any(audio, hwparams)) < 0)
    exit_snd_error(rc, "hardware parameters");

  if ((rc = snd_pcm_hw_params_set_rate_resample(audio, hwparams, 0)) < 0)
    exit_snd_error(rc, "hardware parameters");

  if ((rc = snd_pcm_hw_params_set_access(audio, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
    exit_snd_error(rc, "access type");

  if ((rc = snd_pcm_hw_params_set_format(audio, hwparams, SND_PCM_FORMAT_S16)) < 0)
    exit_snd_error(rc, "sample format");

  if ((rc = snd_pcm_hw_params_set_channels_near(audio, hwparams, &n_channels)) < 0)
    exit_snd_error(rc, "number of channels");

  if ((rc = snd_pcm_hw_params_set_rate_near(audio, hwparams, &samplerate, &dir)) < 0)
    exit_snd_error(rc, "sample rate");

  if ((rc = snd_pcm_hw_params_set_buffer_time_near(audio, hwparams, &buftime, &dir)) < 0)
    exit_snd_error(rc, "buffer time");

  if ((rc = snd_pcm_hw_params_set_period_time_near(audio, hwparams, &pertime, &dir)) < 0)
    exit_snd_error(rc, "period time");

  if ((rc = snd_pcm_hw_params(audio, hwparams)) < 0)
    exit_snd_error(rc, "applying hardware parameters");

  if ((rc = snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize)) < 0)
    exit_snd_error(rc, "buffer size");

  if ((rc = snd_pcm_hw_params_get_period_size(hwparams, &periodsize, &dir)) < 0)
    exit_snd_error(rc, "period size");

  snd_pcm_hw_params_free(hwparams);

  if ((rc = snd_pcm_sw_params_malloc(&swparams)) < 0)
    exit_snd_error(rc, "software parameters");

  if ((rc = snd_pcm_sw_params_current(audio, swparams)) < 0)
    exit_snd_error(rc, "software parameters");

  if ((rc = snd_pcm_sw_params_set_start_threshold(audio, swparams,
                                                  bufsize / periodsize * periodsize)) < 0)
    exit_snd_error(rc, "start threshold");

  if ((rc = snd_pcm_sw_params(audio, swparams)) < 0)
    exit_snd_error(rc, "applying software parameters");

  snd_pcm_sw_params_free(swparams);

  if ((rc = snd_pcm_prepare(audio)) < 0)
    exit_snd_error(rc, "preparing device");
}
Exemplo n.º 15
0
/* set up an input or output device.  Return 0 on success, -1 on failure. */
static int alsaio_setup(t_alsa_dev *dev, int out, int *channels, int *rate,
    int nfrags, int frag_size)
{
    int bufsizeforthis, err;
    snd_pcm_hw_params_t* hw_params;
    snd_pcm_sw_params_t* sw_params;
    unsigned int tmp_uint;
    snd_pcm_uframes_t tmp_snd_pcm_uframes;

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

    if (sys_verbose)
        post((out ? "configuring sound output..." :
            "configuring sound input..."));

        /* set hardware parameters... */

        /* get the default params */
    err = snd_pcm_hw_params_any(dev->a_handle, hw_params);
    check_error(err, out, "snd_pcm_hw_params_any");

        /* try to set interleaved access */
    err = snd_pcm_hw_params_set_access(dev->a_handle,
        hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0)
        return (-1);
    check_error(err, out, "snd_pcm_hw_params_set_access");
#if 0       /* enable this to print out which formats are available */
    {
        int i;
        for (i = 0; i <= SND_PCM_FORMAT_LAST; i++)
            fprintf(stderr, "%d -> %d\n",
                i, snd_pcm_hw_params_test_format(dev->a_handle, hw_params, i));
    }
#endif
        /* Try to set 32 bit format first */
    err = snd_pcm_hw_params_set_format(dev->a_handle,
        hw_params, SND_PCM_FORMAT_S32);
    if (err < 0)
    {
        err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params,
            SND_PCM_FORMAT_S24_3LE);
        if (err < 0)
        {
            err = snd_pcm_hw_params_set_format(dev->a_handle, hw_params,
                SND_PCM_FORMAT_S16);
            check_error(err, out, "_pcm_hw_params_set_format");
            dev->a_sampwidth = 2;
        }
        else dev->a_sampwidth = 3;
    }
    else dev->a_sampwidth = 4;

    if (sys_verbose)
        post("Sample width set to %d bytes", dev->a_sampwidth);

        /* set the subformat */
    err = snd_pcm_hw_params_set_subformat(dev->a_handle,
        hw_params, SND_PCM_SUBFORMAT_STD);
    check_error(err, out, "snd_pcm_hw_params_set_subformat");

        /* set the number of channels */
    tmp_uint = *channels;
    err = snd_pcm_hw_params_set_channels_near(dev->a_handle,
        hw_params, &tmp_uint);
    check_error(err, out, "snd_pcm_hw_params_set_channels");
    if (tmp_uint != (unsigned)*channels)
        post("ALSA: set %s channels to %d", (out?"output":"input"), tmp_uint);
    *channels = tmp_uint;
    dev->a_channels = *channels;

        /* set the sampling rate */
    err = snd_pcm_hw_params_set_rate_near(dev->a_handle, hw_params,
        (unsigned int *)rate, 0);
    check_error(err, out, "snd_pcm_hw_params_set_rate_min");
#if 0
    err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
    post("input sample rate %d", err);
#endif

    /* post("frag size %d, nfrags %d", frag_size, nfrags); */
        /* set "period size" */
    tmp_snd_pcm_uframes = frag_size;
    err = snd_pcm_hw_params_set_period_size_near(dev->a_handle,
        hw_params, &tmp_snd_pcm_uframes, 0);
    check_error(err, out, "snd_pcm_hw_params_set_period_size_near");

        /* set the buffer size */
    tmp_snd_pcm_uframes = nfrags * frag_size;
    err = snd_pcm_hw_params_set_buffer_size_near(dev->a_handle,
        hw_params, &tmp_snd_pcm_uframes);
    check_error(err, out, "snd_pcm_hw_params_set_buffer_size_near");

    err = snd_pcm_hw_params(dev->a_handle, hw_params);
    check_error(err, out, "snd_pcm_hw_params");

        /* set up the buffer */
    bufsizeforthis = DEFDACBLKSIZE * dev->a_sampwidth * *channels;
    if (alsa_snd_buf)
    {
        if (alsa_snd_bufsize < bufsizeforthis)
        {
            if (!(alsa_snd_buf = realloc(alsa_snd_buf, bufsizeforthis)))
            {
                post("out of memory");
                return (-1);
            }
            memset(alsa_snd_buf, 0, bufsizeforthis);
            alsa_snd_bufsize = bufsizeforthis;
        }
    }
    else
    {
        if (!(alsa_snd_buf = (void *)malloc(bufsizeforthis)))
        {
            post("out of memory");
            return (-1);
        }
        memset(alsa_snd_buf, 0, bufsizeforthis);
        alsa_snd_bufsize = bufsizeforthis;
    }

    err = snd_pcm_sw_params_current(dev->a_handle, sw_params);
    if (err < 0)
    {
        post("Unable to determine current swparams for %s: %s\n",
            (out ? "output" : "input"), snd_strerror(err));
        return (-1);
    }
    err = snd_pcm_sw_params_set_stop_threshold(dev->a_handle, sw_params,
        0x7fffffff);
    if (err < 0)
    {
        post("Unable to set start threshold mode for %s: %s\n",
            (out ? "output" : "input"), snd_strerror(err));
        return (-1);
    }

    err = snd_pcm_sw_params_set_avail_min(dev->a_handle, sw_params, 4);
    if (err < 0)
    {
        post("Unable to set avail min for %s: %s\n",
            (out ? "output" : "input"), snd_strerror(err));
        return (-1);
    }
    err = snd_pcm_sw_params(dev->a_handle, sw_params);
    if (err < 0)
    {
        post("Unable to set sw params for %s: %s\n",
            (out ? "output" : "input"), snd_strerror(err));
        return (-1);
    }

    return (0);
}
Exemplo n.º 16
0
int open_alsa_write(struct pcm **p, char *name, int rate, int channels, float seconds)
{
	snd_pcm_t *pcm;
	if (snd_pcm_open(&pcm, name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
		fprintf(stderr, "Error opening PCM device %s\n", name);
		return 0;
	}

	snd_pcm_hw_params_t *params;
	snd_pcm_hw_params_alloca(&params);
	if (snd_pcm_hw_params_any(pcm, params) < 0) {
		fprintf(stderr, "Can not configure this PCM device.\n");
		snd_pcm_close(pcm);
		return 0;
	}

	if (snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
		fprintf(stderr, "Error setting access.\n");
		snd_pcm_close(pcm);
		return 0;
	}

	if (snd_pcm_hw_params_set_format(pcm, params, SND_PCM_FORMAT_S16_LE) < 0) {
		fprintf(stderr, "Error setting S16_LE format.\n");
		snd_pcm_close(pcm);
		return 0;
	}

	if (snd_pcm_hw_params_set_rate_resample(pcm, params, 0) < 0) {
		fprintf(stderr, "Error disabling resampling.\n");
		snd_pcm_close(pcm);
		return 0;
	}

	if (snd_pcm_hw_params_set_rate_near(pcm, params, (unsigned int *)&rate, 0) < 0) {
		fprintf(stderr, "Error setting rate.\n");
		snd_pcm_close(pcm);
		return 0;
	}

	if (snd_pcm_hw_params_set_channels_near(pcm, params, (unsigned int *)&channels) < 0) {
		fprintf(stderr, "Error setting channels.\n");
		snd_pcm_close(pcm);
		return 0;
	}

	if (snd_pcm_hw_params(pcm, params) < 0) {
		fprintf(stderr, "Error setting HW params.\n");
		snd_pcm_close(pcm);
		return 0;
	}

	struct alsa *alsa = (struct alsa *)malloc(sizeof(struct alsa));
	alsa->base.close = close_alsa;
	alsa->base.info = info_alsa;
	alsa->base.rate = rate_alsa;
	alsa->base.channels = channels_alsa;
	alsa->base.rw = write_alsa;
	alsa->base.data = (void *)alsa;

	alsa->pcm = pcm;
	alsa->r = rate;
	alsa->c = channels;
	alsa->frames = seconds * rate;
	alsa->index = 0;
	*p = &(alsa->base);
	return 1;
}
Exemplo n.º 17
0
/**
 * Set up the snd_pcm_t object which was opened by the caller.  Set up
 * the configured settings and the audio format.
 */
static bool
alsa_setup(struct alsa_data *ad, struct audio_format *audio_format,
	   GError **error)
{
	snd_pcm_hw_params_t *hwparams;
	snd_pcm_sw_params_t *swparams;
	unsigned int sample_rate = audio_format->sample_rate;
	unsigned int channels = audio_format->channels;
	snd_pcm_uframes_t alsa_buffer_size;
	snd_pcm_uframes_t alsa_period_size;
	int err;
	const char *cmd = NULL;
	int retry = MPD_ALSA_RETRY_NR;
	unsigned int period_time, period_time_ro;
	unsigned int buffer_time;

	period_time_ro = period_time = ad->period_time;
configure_hw:
	/* configure HW params */
	snd_pcm_hw_params_alloca(&hwparams);
	cmd = "snd_pcm_hw_params_any";
	err = snd_pcm_hw_params_any(ad->pcm, hwparams);
	if (err < 0)
		goto error;

	if (ad->use_mmap) {
		err = snd_pcm_hw_params_set_access(ad->pcm, hwparams,
						   SND_PCM_ACCESS_MMAP_INTERLEAVED);
		if (err < 0) {
			g_warning("Cannot set mmap'ed mode on ALSA device \"%s\":  %s\n",
				  alsa_device(ad), snd_strerror(-err));
			g_warning("Falling back to direct write mode\n");
			ad->use_mmap = false;
		} else
			ad->writei = snd_pcm_mmap_writei;
	}

	if (!ad->use_mmap) {
		cmd = "snd_pcm_hw_params_set_access";
		err = snd_pcm_hw_params_set_access(ad->pcm, hwparams,
						   SND_PCM_ACCESS_RW_INTERLEAVED);
		if (err < 0)
			goto error;
		ad->writei = snd_pcm_writei;
	}

	err = alsa_output_setup_format(ad->pcm, hwparams, audio_format);
	if (err < 0) {
		g_set_error(error, alsa_output_quark(), err,
			    "ALSA device \"%s\" does not support format %s: %s",
			    alsa_device(ad),
			    sample_format_to_string(audio_format->format),
			    snd_strerror(-err));
		return false;
	}

	err = snd_pcm_hw_params_set_channels_near(ad->pcm, hwparams,
						  &channels);
	if (err < 0) {
		g_set_error(error, alsa_output_quark(), err,
			    "ALSA device \"%s\" does not support %i channels: %s",
			    alsa_device(ad), (int)audio_format->channels,
			    snd_strerror(-err));
		return false;
	}
	audio_format->channels = (int8_t)channels;

	err = snd_pcm_hw_params_set_rate_near(ad->pcm, hwparams,
					      &sample_rate, NULL);
	if (err < 0 || sample_rate == 0) {
		g_set_error(error, alsa_output_quark(), err,
			    "ALSA device \"%s\" does not support %u Hz audio",
			    alsa_device(ad), audio_format->sample_rate);
		return false;
	}
	audio_format->sample_rate = sample_rate;

	snd_pcm_uframes_t buffer_size_min, buffer_size_max;
	snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min);
	snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size_max);
	unsigned buffer_time_min, buffer_time_max;
	snd_pcm_hw_params_get_buffer_time_min(hwparams, &buffer_time_min, 0);
	snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time_max, 0);
	g_debug("buffer: size=%u..%u time=%u..%u",
		(unsigned)buffer_size_min, (unsigned)buffer_size_max,
		buffer_time_min, buffer_time_max);

	snd_pcm_uframes_t period_size_min, period_size_max;
	snd_pcm_hw_params_get_period_size_min(hwparams, &period_size_min, 0);
	snd_pcm_hw_params_get_period_size_max(hwparams, &period_size_max, 0);
	unsigned period_time_min, period_time_max;
	snd_pcm_hw_params_get_period_time_min(hwparams, &period_time_min, 0);
	snd_pcm_hw_params_get_period_time_max(hwparams, &period_time_max, 0);
	g_debug("period: size=%u..%u time=%u..%u",
		(unsigned)period_size_min, (unsigned)period_size_max,
		period_time_min, period_time_max);

	if (ad->buffer_time > 0) {
		buffer_time = ad->buffer_time;
		cmd = "snd_pcm_hw_params_set_buffer_time_near";
		err = snd_pcm_hw_params_set_buffer_time_near(ad->pcm, hwparams,
							     &buffer_time, NULL);
		if (err < 0)
			goto error;
	} else {
		err = snd_pcm_hw_params_get_buffer_time(hwparams, &buffer_time,
							NULL);
		if (err < 0)
			buffer_time = 0;
	}

	if (period_time_ro == 0 && buffer_time >= 10000) {
		period_time_ro = period_time = buffer_time / 4;

		g_debug("default period_time = buffer_time/4 = %u/4 = %u",
			buffer_time, period_time);
	}

	if (period_time_ro > 0) {
		period_time = period_time_ro;
		cmd = "snd_pcm_hw_params_set_period_time_near";
		err = snd_pcm_hw_params_set_period_time_near(ad->pcm, hwparams,
							     &period_time, NULL);
		if (err < 0)
			goto error;
	}

	cmd = "snd_pcm_hw_params";
	err = snd_pcm_hw_params(ad->pcm, hwparams);
	if (err == -EPIPE && --retry > 0 && period_time_ro > 0) {
		period_time_ro = period_time_ro >> 1;
		goto configure_hw;
	} else if (err < 0)
Exemplo n.º 18
0
int main(int argc, char ** argv) {
    
    // Variable declaration
	int rc;
	char * buffer;
  	int buffer_size;
  	int periods_per_buffer;

  	snd_pcm_t *handle;
  	snd_pcm_hw_params_t *params;
  	snd_pcm_uframes_t frames;

  	unsigned int channels;
  	unsigned int rate;

	wav_header * wav_header_info;

  	FILE * fp;

    
    // Argument parsing
  	if (argc != 2)
	{
        printf("Incorrect usage: Enter filename of the wav file you want to play as an argument: %s filename.txt\n", argv[0]);
		return 1;
	}

    
    // Open wav file to read
	fp = fopen(argv[1], "rb");

	if (fp == NULL)
	{
		printf("ERROR: %s does not exist, or cannot be opened.\n", argv[1]);
		return 1;
	}

	wav_header_info = malloc(44);

	fread(wav_header_info, 1, 44, fp);
    

	// print_wav_header(wav_header_info);

    
    // Assign variables that were read from the wave file
	channels = wav_header_info->number_of_channels;
	rate = wav_header_info->sample_rate;
	periods_per_buffer = 2; // Down to user preference, depending on size of internal ring buffer of ALSA


  	// Open PCM device for playback
  	if ((rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) 
  	{
    	printf("ERROR: Cannot open pcm device. %s\n", snd_strerror(rc));
  	}

    
  	// Allocate hardware parameters
  	if ((rc = snd_pcm_hw_params_malloc(&params)) < 0)
  	{
  		printf("ERROR: Cannot allocate hardware parameters. %s\n", snd_strerror(rc));
  	}

    
  	// Initialize parameters with default values
  	if ((rc = snd_pcm_hw_params_any(handle, params)) < 0)
  	{
  		printf("ERROR: Cannot initialize hardware parameters. %s\n", snd_strerror(rc));
  	}


  	// Setting hardware parameters
  	if ((rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
  	{
  		printf("ERROR: Cannot set interleaved mode. %s\n", snd_strerror(rc));
  	}

  	if ((rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE)) < 0)
  	{
  		printf("ERROR: Cannot set PCM format. %s\n", snd_strerror(rc));
  	}

  	if ((rc = snd_pcm_hw_params_set_channels_near(handle, params, &channels)) < 0)
  	{
  		printf("ERROR: Cannot set number of channels. %s\n", snd_strerror(rc));
  	}

 	if ((rc = snd_pcm_hw_params_set_rate_near(handle, params, &rate, 0)) < 0)
 	{
 		printf("ERROR: Cannot set plyabck rate. %s\n", snd_strerror(rc));
 	}

 	if ((rc = snd_pcm_hw_params(handle, params)) < 0)
 	{
 		printf("ERROR: Cannot set hardware parameters. %s\n", snd_strerror(rc));
 	}


 	// Get hardware parameters
 	if ((rc = snd_pcm_hw_params_get_period_size(params, &frames, 0)) < 0)
	{
		printf("Playback ERROR: Can't get period size. %s\n", snd_strerror(rc));
	}
	printf("Frames: %lu\n", frames);

	if ((rc = snd_pcm_hw_params_get_channels(params, &channels)) < 0)
	{
		printf("Playback ERROR: Can't get channel number. %s\n", snd_strerror(rc));
	}

	if ((rc = snd_pcm_hw_params_get_rate(params, &rate, 0)) < 0)
	{
		printf("ERROR: Cannot get rate. %s\n", snd_strerror(rc));
	}


	// Free paraemeters
	snd_pcm_hw_params_free(params);


	// Create buffer
  	buffer_size = frames * periods_per_buffer * channels * sizeof(int16_t); /* 2 bytes/sample, 2 channels */
  	buffer = (char *) malloc(buffer_size);

  	// Send info to ALSA
 	//while ((rc = read(0, buffer, buffer_size)) != 0) 
 	while (rc = fread(buffer, 1, periods_per_buffer * frames * channels * sizeof(int16_t), fp) != 0)
 	{
    	rc = snd_pcm_writei(handle, buffer, frames * periods_per_buffer);
    	if (rc == -EPIPE) 
    	{
      		fprintf(stderr, "underrun occurred\n");
      		snd_pcm_prepare(handle);
    	} 
    	else if (rc < 0) 
    	{
      		printf("ERROR: Cannot write to playback device. %s\n", strerror(rc));
    	}
  	}

  	printf("Info set: Device is now draining...\n");
  	snd_pcm_drain(handle);

  	printf("Done playing, closing connections.\n");
  	snd_pcm_close(handle);

  	free(wav_header_info);
  	free(buffer);
  	fclose(fp);

  return 0;
}
Exemplo n.º 19
0
static int
alsa_setup(struct snd_format* f) {
	int err;
	snd_pcm_hw_params_t* hwparams;
	snd_pcm_sw_params_t* swparams;
	unsigned int alsa_buffer_time, alsa_period_time;
	snd_pcm_uframes_t alsa_buffer_size, alsa_period_size;

	free(outputf);
	outputf = snd_format_alloc(f->rate, f->channels);

	printf("  Opening device %s ... ", alsa_cb.pcm_device);

	if((err = snd_pcm_open(&alsa_pcm, alsa_cb.pcm_device,
	                       SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
		printf("alsa_setup(): Failed to open pcm device (%s): %s\n",
		       alsa_cb.pcm_device, snd_strerror(-err));
		alsa_pcm = NULL;
		free(outputf);
		outputf = NULL;
		return -1;
	}

	/* doesn't care about non-blocking */
	/* snd_pcm_nonblock(alsa_pcm, 0); */

	if(0) {           //debug
		snd_pcm_info_t* info;
		int alsa_card, alsa_device, alsa_subdevice;

		snd_pcm_info_alloca(&info);
		snd_pcm_info(alsa_pcm, info);
		alsa_card = snd_pcm_info_get_card(info);
		alsa_device = snd_pcm_info_get_device(info);
		alsa_subdevice = snd_pcm_info_get_subdevice(info);
		printf("Card %i, Device %i, Subdevice %i\n",
		       alsa_card, alsa_device, alsa_subdevice);
	}

	snd_pcm_hw_params_alloca(&hwparams);

	if((err = snd_pcm_hw_params_any(alsa_pcm, hwparams)) < 0) {
		printf("alsa_setup(): No configuration available for "
		       "playback: %s\n", snd_strerror(-err));
		return -1;
	}

	if((err = snd_pcm_hw_params_set_access(alsa_pcm, hwparams,
	                                       SND_PCM_ACCESS_RW_INTERLEAVED)) <
	    0) {
		printf("alsa_setup(): Cannot set direct write mode: %s\n",
		       snd_strerror(-err));
		return -1;
	}

	if((err =
	      snd_pcm_hw_params_set_format(alsa_pcm, hwparams,
	                                   outputf->format)) < 0) {
		printf("alsa_setup(): Sample format not "
		       "available for playback: %s\n", snd_strerror(-err));
		return -1;
	}

	if((err = snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams,
	                                              &outputf->channels)) < 0) {
		printf
		("alsa_setup(): snd_pcm_hw_params_set_channels_near failed: %s.\n",
		 snd_strerror(-err));
		return -1;
	}

	snd_pcm_hw_params_set_rate_near(alsa_pcm, hwparams, &outputf->rate, 0);

	if(outputf->rate == 0) {
		printf("alsa_setup(): No usable samplerate available.\n");
		return -1;
	}

	outputf->sample_bits = snd_pcm_format_physical_width(outputf->format);
	outputf->bps =
	  (outputf->rate * outputf->sample_bits * outputf->channels) >> 3;

	alsa_buffer_time = alsa_cb.buffer_time * 1000;

	if((err = snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams,
	                                                 &alsa_buffer_time,
	                                                 0)) < 0) {
		printf("alsa_setup(): Set buffer time failed: %s.\n",
		       snd_strerror(-err));
		return -1;
	}

	alsa_period_time = alsa_cb.period_time * 1000;

	if((err = snd_pcm_hw_params_set_period_time_near(alsa_pcm, hwparams,
	                                                 &alsa_period_time,
	                                                 0)) < 0) {
		printf("alsa_setup(): Set period time failed: %s.\n",
		       snd_strerror(-err));
		return -1;
	}

	if(snd_pcm_hw_params(alsa_pcm, hwparams) < 0) {
		printf("alsa_setup(): Unable to install hw params\n");
		return -1;
	}

	if((err =
	      snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size)) < 0) {
		printf("alsa_setup(): snd_pcm_hw_params_get_buffer_size() "
		       "failed: %s\n", snd_strerror(-err));
		return -1;
	}

	if((err =
	      snd_pcm_hw_params_get_period_size(hwparams, &alsa_period_size,
	                                        0)) < 0) {
		printf("alsa_setup(): snd_pcm_hw_params_get_period_size() "
		       "failed: %s\n", snd_strerror(-err));
		return -1;
	}

	snd_pcm_sw_params_alloca(&swparams);
	snd_pcm_sw_params_current(alsa_pcm, swparams);

	if((err = snd_pcm_sw_params_set_start_threshold(alsa_pcm,
	                                                swparams,
	                                                alsa_buffer_size -
	                                                alsa_period_size) < 0))
		printf("alsa_setup(): setting start " "threshold failed: %s\n",
		       snd_strerror(-err));

	if(snd_pcm_sw_params(alsa_pcm, swparams) < 0) {
		printf("alsa_setup(): Unable to install sw params\n");
		return -1;
	}

	hw_buffer_size = snd_pcm_frames_to_bytes(alsa_pcm, alsa_buffer_size);
	hw_period_size = snd_pcm_frames_to_bytes(alsa_pcm, alsa_period_size);

	if(inputf->bps != outputf->bps) {
		int align = (inputf->sample_bits * inputf->channels) / 8;
		hw_buffer_size_in = ((u_int) hw_buffer_size * inputf->bps +
		                     outputf->bps / 2) / outputf->bps;
		hw_period_size_in = ((u_int) hw_period_size * inputf->bps +
		                     outputf->bps / 2) / outputf->bps;
		hw_buffer_size_in -= hw_buffer_size_in % align;
		hw_period_size_in -= hw_period_size_in % align;
	} else {
		hw_buffer_size_in = hw_buffer_size;
		hw_period_size_in = hw_period_size;
	}

#if 0
	printf("Device setup: buffer time: %i, size: %i.\n", alsa_buffer_time,
	       hw_buffer_size);
	printf("Device setup: period time: %i, size: %i.\n", alsa_period_time,
	       hw_period_size);
	printf("bits per sample: %i; frame size: %i; Bps: %i\n",
	       snd_pcm_format_physical_width(outputf->format),
	       snd_pcm_frames_to_bytes(alsa_pcm, 1), outputf->bps);
#endif
	printf("success.\n");
	return 0;
}
Exemplo n.º 20
0
bool OutputALSA::initialize(quint32 freq, ChannelMap map, Qmmp::AudioFormat format)
{
    m_inited = false;

    if (pcm_handle)
        return false;

    if (snd_pcm_open(&pcm_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0)
    {
        qWarning ("OutputALSA: Error opening PCM device %s", pcm_name);
        return false;
    }

    // we need to configure

    uint rate = freq; /* Sample rate */
    uint exact_rate = freq;   /* Sample rate returned by */

    /* load settings from config */
    QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
    settings.beginGroup("ALSA");
    uint buffer_time = settings.value("buffer_time",500).toUInt()*1000;
    uint period_time = settings.value("period_time",100).toUInt()*1000;
    bool use_pause =  settings.value("use_snd_pcm_pause", false).toBool();
    settings.endGroup();

    snd_pcm_hw_params_t *hwparams = 0;
    snd_pcm_sw_params_t *swparams = 0;
    int err; //alsa error code

    //hw params
    snd_pcm_hw_params_alloca(&hwparams);
    if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0)
    {
        qWarning("OutputALSA: Can not read configuration for PCM device: %s", snd_strerror(err));
        return false;
    }
    if (m_use_mmap)
    {
        if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0)
        {
            qWarning("OutputALSA: Error setting mmap access: %s", snd_strerror(err));
            m_use_mmap = false;
        }
    }
    if (!m_use_mmap)
    {
        if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
        {
            qWarning("OutputALSA: Error setting access: %s", snd_strerror(err));
            return false;
        }
    }
    snd_pcm_format_t alsa_format = SND_PCM_FORMAT_UNKNOWN;
    switch (format)
    {
    case Qmmp::PCM_S8:
        alsa_format = SND_PCM_FORMAT_S8;
        break;
    case Qmmp::PCM_S16LE:
        alsa_format = SND_PCM_FORMAT_S16_LE;
        break;
    case Qmmp::PCM_S24LE:
        alsa_format = SND_PCM_FORMAT_S24_LE;
        break;
    case Qmmp::PCM_S32LE:
        alsa_format = SND_PCM_FORMAT_S32_LE;
        break;
    default:
        qWarning("OutputALSA: unsupported format detected");
        return false;
    }
    if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, alsa_format)) < 0)
    {
        qDebug("OutputALSA: Error setting format: %s", snd_strerror(err));
        return false;
    }
    exact_rate = rate;

    if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0)) < 0)
    {
        qWarning("OutputALSA: Error setting rate: %s", snd_strerror(err));
        return false;
    }
    if (rate != exact_rate)
    {
        qWarning("OutputALSA: The rate %d Hz is not supported by your hardware.\n==> Using %d Hz instead.", rate, exact_rate);
        rate = exact_rate;
    }
    uint c = map.count();
    if ((err = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0)
    {
        qWarning("OutputALSA: Error setting channels: %s", snd_strerror(err));
        return false;
    }
    if (c != (uint)map.count())
    {
        qWarning("OutputALSA: The channel number %d is not supported by your hardware", map.count());
        qWarning("==> Using %d instead.", c);
    }
    if ((err = snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &period_time ,0)) < 0)
    {
        qWarning("OutputALSA: Error setting period time: %s", snd_strerror(err));
        return false;
    }
    if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffer_time ,0)) < 0)
    {
        qWarning("OutputALSA: Error setting buffer time: %s", snd_strerror(err));
        return false;
    }
    if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0)
    {
        qWarning("OutputALSA: Error setting HW params: %s", snd_strerror(err));
        return false;
    }
    //read some alsa parameters
    snd_pcm_uframes_t buffer_size = 0;
    snd_pcm_uframes_t period_size = 0;
    if ((err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size)) < 0)
    {
        qWarning("OutputALSA: Error reading buffer size: %s", snd_strerror(err));
        return false;
    }
    if ((err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0)) < 0)
    {
        qWarning("OutputALSA: Error reading period size: %s", snd_strerror(err));
        return false;
    }
    //swparams
    snd_pcm_sw_params_alloca(&swparams);
    snd_pcm_sw_params_current(pcm_handle, swparams);
    if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,
               buffer_size - period_size)) < 0)
        qWarning("OutputALSA: Error setting threshold: %s", snd_strerror(err));
    if ((err = snd_pcm_sw_params(pcm_handle, swparams)) < 0)
    {
        qWarning("OutputALSA: Error setting SW params: %s", snd_strerror(err));
        return false;
    }
    //setup needed values
    m_chunk_size = period_size;
    m_can_pause = snd_pcm_hw_params_can_pause(hwparams) && use_pause;
    qDebug("OutputALSA: can pause: %d", m_can_pause);

    ChannelMap out_map = map;
#if (SND_LIB_VERSION >= 0x01001B)
    //channel map configuration
    snd_pcm_chmap_t *chmap = snd_pcm_get_chmap(pcm_handle);
    if(chmap)
    {
        out_map.clear();
        char tmp[256];
        memset(tmp,0,256);
        snd_pcm_chmap_print(chmap, 256, tmp);
        qDebug("OutputALSA: received channel map: %s",tmp);

        for(uint i = 0; i < chmap->channels; ++i)
        {
            if(m_alsa_channels.keys().contains(chmap->pos[i]))
                out_map.append(m_alsa_channels.value(chmap->pos[i]));
            else
                out_map.append(Qmmp::CHAN_NULL);
        }
        free(chmap);
    }
    else
        qWarning("OutputALSA: Unable to receive current channel map");
#endif
    configure(exact_rate, out_map, format); //apply configuration
    //create alsa prebuffer;
    m_prebuf_size = 2 * snd_pcm_frames_to_bytes(pcm_handle, m_chunk_size); //buffer for two periods
    m_prebuf = (uchar *)malloc(m_prebuf_size);
    m_inited = true;
    return true;
}
Exemplo n.º 21
0
bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
{
  snd_pcm_hw_params_t *hw_params;

  snd_pcm_hw_params_alloca(&hw_params);
  memset(hw_params, 0, snd_pcm_hw_params_sizeof());

  snd_pcm_hw_params_any(m_pcm, hw_params);
  snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);

  unsigned int sampleRate   = format.m_sampleRate;
  unsigned int channelCount = format.m_channelLayout.Count();
  snd_pcm_hw_params_set_rate_near    (m_pcm, hw_params, &sampleRate, NULL);
  snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount);

  /* ensure we opened X channels or more */
  if (format.m_channelLayout.Count() > channelCount)
  {
    CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to open the required number of channels");
    return false;
  }

  /* update the channelLayout to what we managed to open */
  format.m_channelLayout.Reset();
  for (unsigned int i = 0; i < channelCount; ++i)
    format.m_channelLayout += ALSAChannelMap[i];

  snd_pcm_format_t fmt = AEFormatToALSAFormat(format.m_dataFormat);
  if (fmt == SND_PCM_FORMAT_UNKNOWN)
  {
    /* if we dont support the requested format, fallback to float */
    format.m_dataFormat = AE_FMT_FLOAT;
    fmt                 = SND_PCM_FORMAT_FLOAT;
  }

  /* try the data format */
  if (snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
  {
    /* if the chosen format is not supported, try each one in decending order */
    CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(format.m_dataFormat));
    for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
    {
      if (AE_IS_RAW(i) || i == AE_FMT_MAX)
        continue;

      if (m_passthrough && i != AE_FMT_S16BE && i != AE_FMT_S16LE)
	continue;

      fmt = AEFormatToALSAFormat(i);

      if (fmt == SND_PCM_FORMAT_UNKNOWN || snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
      {
        fmt = SND_PCM_FORMAT_UNKNOWN;
        continue;
      }

      int fmtBits = CAEUtil::DataFormatToBits(i);
      int bits    = snd_pcm_hw_params_get_sbits(hw_params);
      if (bits != fmtBits)
      {
        /* if we opened in 32bit and only have 24bits, pack into 24 */
        if (fmtBits == 32 && bits == 24)
          i = AE_FMT_S24NE4;
        else
          continue;
      }

      /* record that the format fell back to X */
      format.m_dataFormat = i;
      CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
      break;
    }

    /* if we failed to find a valid output format */
    if (fmt == SND_PCM_FORMAT_UNKNOWN)
    {
      CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to find a suitable output format");
      return false;
    }
  }

  unsigned int periods;

  snd_pcm_uframes_t periodSize, bufferSize;
  snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize);

  bufferSize  = std::min(bufferSize, (snd_pcm_uframes_t)8192);
  periodSize  = bufferSize / ALSA_PERIODS;
  periods     = ALSA_PERIODS;

  CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize);

  /* work on a copy of the hw params */
  snd_pcm_hw_params_t *hw_params_copy;
  snd_pcm_hw_params_alloca(&hw_params_copy);

  /* try to set the buffer size then the period size */
  snd_pcm_hw_params_copy(hw_params_copy, hw_params);
  snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
  snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
  snd_pcm_hw_params_set_periods_near    (m_pcm, hw_params_copy, &periods   , NULL);
  if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
  {
    /* try to set the period size then the buffer size */
    snd_pcm_hw_params_copy(hw_params_copy, hw_params);
    snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
    snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
    snd_pcm_hw_params_set_periods_near    (m_pcm, hw_params_copy, &periods   , NULL);
    if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
    {
      /* try to just set the buffer size */
      snd_pcm_hw_params_copy(hw_params_copy, hw_params);
      snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
      snd_pcm_hw_params_set_periods_near    (m_pcm, hw_params_copy, &periods   , NULL);
      if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
      {
        /* try to just set the period size */
        snd_pcm_hw_params_copy(hw_params_copy, hw_params);
        snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
        snd_pcm_hw_params_set_periods_near    (m_pcm, hw_params_copy, &periods   , NULL);
        if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
        {
          CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Failed to set the parameters");
          return false;
        }
      }
    }
  }

  snd_pcm_hw_params_get_period_size(hw_params_copy, &periodSize, NULL);
  snd_pcm_hw_params_get_buffer_size(hw_params_copy, &bufferSize);
  

  CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize);

  /* set the format parameters */
  format.m_sampleRate   = sampleRate;
  format.m_frames       = periodSize;
  format.m_frameSamples = periodSize * format.m_channelLayout.Count();
  format.m_frameSize    = snd_pcm_frames_to_bytes(m_pcm, 1);

  m_bufferSize = (unsigned int)bufferSize;
  m_timeout    = std::ceil((double)(bufferSize * 1000) / (double)sampleRate);

  CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Setting timeout to %d ms", m_timeout);

  return true;
}
Exemplo n.º 22
0
static void SetOptions(unsigned int rate, int opt)
{
	int err;
	snd_pcm_format_t format;
	unsigned int val;
	/* start with setting default values, if we bail out */
	plrRate=rate;
	plrOpt=opt;

	alsaOpenDevice();
	if (!alsa_pcm)
		return;

#ifdef ALSA_DEBUG
	fprintf(stderr, "ALSA snd_pcm_hw_params_any(alsa_pcm, hwparams) = ");
#endif
	if ((err=snd_pcm_hw_params_any(alsa_pcm, hwparams))<0) /* we need to check for <0 here, due to a bug in the ALSA PulseAudio plugin */
	{
#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
		fprintf(stderr, "ALSA: snd_pcm_hw_params_any() failed: %s\n", snd_strerror(-err));
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok\n");
	fprintf(stderr, "ALSA snd_pcm_hw_params_set_access(alsa_pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) = ");
#endif

	if ((err=snd_pcm_hw_params_set_access(alsa_pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)))
	{

#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
		fprintf(stderr, "ALSA: snd_pcm_hw_params_set_access() failed: %s\n", snd_strerror(-err));
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok\n");
#endif
	if (opt&PLR_16BIT)
		if (opt&PLR_SIGNEDOUT)
			format=SND_PCM_FORMAT_S16;
		else
			format=SND_PCM_FORMAT_U16;
	else
		if (opt&PLR_SIGNEDOUT)
			format=SND_PCM_FORMAT_S8;
		else
			format=SND_PCM_FORMAT_U8;
#ifdef ALSA_DEBUG
	fprintf(stderr, "ALSA snd_pcm_hw_params_set_format(alsa_pcm, hwparams, format %i) = ", format);
#endif
	if ((err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, format)))
	{
#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
		fprintf(stderr, "ALSA snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_S16) = ");
#endif
		if ((err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_S16))==0)
		{
			opt|=PLR_16BIT|PLR_SIGNEDOUT;
		} else {
#ifdef ALSA_DEBUG
			fprintf(stderr, "failed: %s\n", snd_strerror(-err));
			fprintf(stderr, "ALSA snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_U16) = ");
#endif
			if ((err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_U16))==0)
			{
				opt&=~(PLR_16BIT|PLR_SIGNEDOUT);
				opt|=PLR_16BIT;
			} else 
			{
#ifdef ALSA_DEBUG
			fprintf(stderr, "failed: %s\n", snd_strerror(-err));
			fprintf(stderr, "ALSA snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_S8) = ");
#endif
			if ((err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_S8))>=0)
				{
					opt&=~(PLR_16BIT|PLR_SIGNEDOUT);
					opt|=PLR_SIGNEDOUT;
				} else 
				{
#ifdef ALSA_DEBUG
				fprintf(stderr, "failed: %s\n", snd_strerror(-err));
				fprintf(stderr, "ALSA snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_U8) = ");
#endif
					if ((err=snd_pcm_hw_params_set_format(alsa_pcm, hwparams, SND_PCM_FORMAT_U8))>=0)
					{
						opt&=~(PLR_16BIT|PLR_SIGNEDOUT);
					} else {
#ifdef ALSA_DEBUG
						fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
						fprintf(stderr, "ALSA: snd_pcm_hw_params_set_format() failed: %s\n", snd_strerror(-err));
						return;
					}
				}
			}
		}
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok\n");
#endif
	bit16=!!(opt&PLR_16BIT);
	if (opt&PLR_STEREO)
		val=2;
	else
		val=1;
#ifdef ALSA_DEBUG
	fprintf(stderr, "ALSA snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &channels=%i) = ", val);
#endif
	if ((err=snd_pcm_hw_params_set_channels_near(alsa_pcm, hwparams, &val))<0)
	{
#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
		fprintf(stderr, "ALSA: snd_pcm_hw_params_set_channels_near() failed: %s\n", snd_strerror(-err));
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok (channels=%i)\n", val);
#endif
	if (val==1)
	{
		stereo=0;
		opt&=~PLR_STEREO;
	} else if (val==2)
	{
		stereo=1;
		opt|=PLR_STEREO;
	} else {
		fprintf(stderr, "ALSA: snd_pcm_hw_params_set_channels_near() gave us %d channels\n", val);
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ALSA snd_pcm_hw_params_set_rate_near(alsa_pcm, hwparams, &rate = %i, 0) = ", rate);
#endif
	if ((err=snd_pcm_hw_params_set_rate_near(alsa_pcm, hwparams, &rate, 0))<0)
	{
#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
		fprintf(stderr, "ALSA: snd_pcm_hw_params_set_rate_near() failed: %s\n", snd_strerror(-err));
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok, rate=%i\n", rate);
#endif
	if (rate==0)
	{
		fprintf(stderr, "ALSA: No usable samplerate available.\n");
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ALSA snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams, 500000 uS, 0) = ");
#endif
	val = 500000;
	if ((err=snd_pcm_hw_params_set_buffer_time_near(alsa_pcm, hwparams, &val, 0)))
	{
#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
		fprintf(stderr, "ALSA: snd_pcm_hw_params_set_buffer_time_near() failed: %s\n", snd_strerror(-err));
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok, latency = %d uS\n", val);
	fprintf(stderr, "ALSA snd_pcm_hw_params(alsa_pcm, hwparams) = ");
#endif
	if ((err=snd_pcm_hw_params(alsa_pcm, hwparams))<0)
	{
#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
		fprintf(stderr, "ALSA: snd_pcm_hw_params() failed: %s\n", snd_strerror(-err));
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok\n");
	fprintf(stderr, "ALSA snd_pcm_sw_params_current(alsa_pcm, swparams) = ");
#endif
	if ((err=snd_pcm_sw_params_current(alsa_pcm, swparams))<0)
	{
#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
		fprintf(stderr, "ALSA: snd_pcm_sw_params_any() failed: %s\n", snd_strerror(-err));
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok\n");
	fprintf(stderr, "ALSA snd_pcm_sw_params(alsa_pcm, swparams) = ");
#endif
	if ((err=snd_pcm_sw_params(alsa_pcm, swparams))<0)
	{
#ifdef ALSA_DEBUG
		fprintf(stderr, "failed: %s\n", snd_strerror(-err));
#endif
		fprintf(stderr, "ALSA: snd_pcm_sw_params() failed: %s\n", snd_strerror(-err));
		return;
	}
#ifdef ALSA_DEBUG
	fprintf(stderr, "ok\n");
#endif
	plrRate=rate;
	plrOpt=opt;
}
Exemplo n.º 23
0
static int ao_alsa_init(dtaudio_output_t *aout, dtaudio_para_t *para)
{
    memcpy(&wrapper->para, para, sizeof(dtaudio_para_t));
    snd_pcm_t *alsa_handle;
    snd_pcm_hw_params_t *alsa_hwparams;
    snd_pcm_sw_params_t *alsa_swparams;
    snd_pcm_uframes_t size;
    snd_pcm_uframes_t boundary;

    alsa_ctx_t *ctx = (alsa_ctx_t *)malloc(sizeof(*ctx));
    if (!ctx) {
        return -1;
    }
    wrapper->ao_priv = ctx;

    int afmt = format_to_alsa(wrapper->para.bps);
    uint32_t channels = wrapper->para.dst_channels;
    uint32_t sr = wrapper->para.dst_samplerate;
    int bytes_per_sample = snd_pcm_format_physical_width(afmt) * channels / 8;

    int err = 0;
    err = snd_pcm_open(&alsa_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        free(ctx);
        wrapper->ao_priv = NULL;
        return -1;
    }

    snd_pcm_hw_params_alloca(&alsa_hwparams);
    snd_pcm_sw_params_alloca(&alsa_swparams);

    err = snd_pcm_hw_params_any(alsa_handle, alsa_hwparams);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params_set_access(alsa_handle, alsa_hwparams,
                                       SND_PCM_ACCESS_RW_INTERLEAVED);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params_set_format(alsa_handle, alsa_hwparams, afmt);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params_set_channels_near(alsa_handle, alsa_hwparams,
            &channels);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_hwparams, &sr, NULL);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    err = snd_pcm_hw_params(alsa_handle, alsa_hwparams);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
    /******************************************************************
     *  Set HW Params Finish
    ******************************************************************/

    /* buffer size means the entire size of alsa pcm buffer size*/
    err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &size);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    ctx->buf_size = size * bytes_per_sample;

    /*period size means count processed every interrupt*/
    err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &size, NULL);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
    ctx->trunk_size = size * bytes_per_sample;

    dt_info(TAG, "outburst: %d, bytes_per_sample: %d, buffersize: %d\n",
            ctx->trunk_size, bytes_per_sample, ctx->buf_size);

    /******************************************************************
    * set sw params
    ******************************************************************/
    err = snd_pcm_sw_params_current(alsa_handle, alsa_swparams);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
#if SND_LIB_VERSION >= 0x000901
    err = snd_pcm_sw_params_get_boundary(alsa_swparams, &boundary);
#else
    boundary = 0x7fffffff;
#endif
    err = snd_pcm_sw_params_set_start_threshold(alsa_handle, alsa_swparams, size);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
    err = snd_pcm_sw_params_set_stop_threshold(alsa_handle, alsa_swparams,
            boundary);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
#if SND_LIB_VERSION >= 0x000901
    err = snd_pcm_sw_params_set_silence_size(alsa_handle, alsa_swparams, boundary);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }
#endif

    err = snd_pcm_sw_params(alsa_handle, alsa_swparams);
    if (err < 0) {
        dt_error(TAG, "%s,%d: %s\n", __func__, __LINE__, snd_strerror(err));
        return -1;
    }

    ctx->pause_support = snd_pcm_hw_params_can_pause(alsa_hwparams);

    //buf size limit
    ctx->buf_threshold = bytes_per_sample * sr * DEFAULT_TIME_SIZE / 1000;
    dt_info(TAG, "alsa audio init ok! outburst:%d thres:%d \n", ctx->trunk_size,
            ctx->buf_threshold);
    ctx->handle = alsa_handle;
    ctx->channels = wrapper->para.dst_channels;
    ctx->bps = wrapper->para.bps;
    ctx->samplerate = wrapper->para.dst_samplerate;
    return 0;
}
Exemplo n.º 24
0
snd_pcm_t *OpenDev( const char *pcm_dev,
                    unsigned int *channels,
                    unsigned int *frequency,
                    snd_pcm_uframes_t *buffsize,
                    snd_pcm_uframes_t *periodsize,
                    unsigned int *periodtime,
                    int *hard_pause){

    snd_pcm_t *mhandle;
    snd_pcm_hw_params_t *hwparams;
    unsigned int periods=2;
    unsigned int exactrate = *frequency;

    // The compiler might warn us because the expansion starts with
    // assert(&hwparams)
    snd_pcm_hw_params_alloca(&hwparams);

    if (snd_pcm_open(&mhandle,pcm_dev,SND_PCM_STREAM_CAPTURE,SND_PCM_ASYNC)<0){
        fprintf(stderr, "Couldn't open PCM device %s\n", pcm_dev);
        return NULL;
    }
    else
        fprintf(stderr, "Opened PCM device %s\n", pcm_dev);
    if (snd_pcm_hw_params_any(mhandle, hwparams)<0){
        fprintf(stderr, "Couldn't configure PCM device.\n");
        return NULL;
    }
    if (snd_pcm_hw_params_set_access(mhandle,
                                     hwparams,
                                     SND_PCM_ACCESS_RW_INTERLEAVED)<0){
        fprintf(stderr, "Couldn't set access.\n");
        return NULL;
    }
    if (snd_pcm_hw_params_set_format(mhandle,
                                     hwparams,
                                     SND_PCM_FORMAT_S16_LE)<0){
        fprintf(stderr, "Couldn't set format.\n");
        return NULL;
    }
    if (snd_pcm_hw_params_set_rate_near(mhandle, hwparams, &exactrate, 0)<0){
        fprintf(stderr, "Couldn't set frequency.\n");
        return NULL;
    }
    if (*frequency != exactrate){
        fprintf(stderr, "Playback frequency %dHz is not available...\n"
                        "Using %dHz instead.\n",*frequency,exactrate);
        *frequency=exactrate;
    }
    if (snd_pcm_hw_params_set_channels_near(mhandle, hwparams, channels)<0){
        fprintf(stderr, "Couldn't set channels number.\n");
        return NULL;
    }
    if(*channels>2){
        fprintf(stderr,"Channels number should be 1(mono) or 2(stereo).\n");
        return NULL;
    }
    if (snd_pcm_hw_params_set_periods_near(mhandle,hwparams,&periods,0)<0){
        fprintf(stderr, "Couldn't set periods.\n");
        return NULL;
    }

    if (snd_pcm_hw_params_set_buffer_size_near(mhandle,hwparams,buffsize)<0){
        fprintf(stderr, "Couldn't set buffer size.\n");
        return NULL;
    }
    if (snd_pcm_hw_params(mhandle,hwparams)<0){
        fprintf(stderr, "Couldn't set hardware parameters.\n");
        return NULL;
    }
    if(hard_pause!=NULL)
        if(!snd_pcm_hw_params_can_pause(hwparams)){
            *hard_pause=1;
        }
    if(periodsize!=NULL)
        snd_pcm_hw_params_get_period_size(hwparams,periodsize,0);

    if(periodtime!=NULL)
        snd_pcm_hw_params_get_period_time(hwparams,periodtime,0);
    fprintf(stderr,"Recording on device %s is set to:\n%d channels at %dHz\n",
                   pcm_dev,*channels,*frequency);
    snd_pcm_prepare(mhandle);

    return mhandle;
}
Exemplo n.º 25
0
bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
{
  snd_pcm_hw_params_t *hw_params;

  snd_pcm_hw_params_alloca(&hw_params);
  memset(hw_params, 0, snd_pcm_hw_params_sizeof());

  snd_pcm_hw_params_any(m_pcm, hw_params);
  snd_pcm_hw_params_set_access(m_pcm, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);

  unsigned int sampleRate   = format.m_sampleRate;
  unsigned int channelCount = format.m_channelLayout.Count();
  snd_pcm_hw_params_set_rate_near    (m_pcm, hw_params, &sampleRate, NULL);
  snd_pcm_hw_params_set_channels_near(m_pcm, hw_params, &channelCount);

  /* ensure we opened X channels or more */
  if (format.m_channelLayout.Count() > channelCount)
  {
    CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Unable to open the required number of channels");
  }

  /* update the channelLayout to what we managed to open */
  format.m_channelLayout.Reset();
  for (unsigned int i = 0; i < channelCount; ++i)
    format.m_channelLayout += ALSAChannelMap[i];

  snd_pcm_format_t fmt = AEFormatToALSAFormat(format.m_dataFormat);
  if (fmt == SND_PCM_FORMAT_UNKNOWN)
  {
    /* if we dont support the requested format, fallback to float */
    format.m_dataFormat = AE_FMT_FLOAT;
    fmt                 = SND_PCM_FORMAT_FLOAT;
  }

  /* try the data format */
  if (snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
  {
    /* if the chosen format is not supported, try each one in decending order */
    CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Your hardware does not support %s, trying other formats", CAEUtil::DataFormatToStr(format.m_dataFormat));
    for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1))
    {
      if (AE_IS_RAW(i) || i == AE_FMT_MAX)
        continue;

      if (m_passthrough && i != AE_FMT_S16BE && i != AE_FMT_S16LE)
	continue;

      fmt = AEFormatToALSAFormat(i);

      if (fmt == SND_PCM_FORMAT_UNKNOWN || snd_pcm_hw_params_set_format(m_pcm, hw_params, fmt) < 0)
      {
        fmt = SND_PCM_FORMAT_UNKNOWN;
        continue;
      }

      int fmtBits = CAEUtil::DataFormatToBits(i);
      int bits    = snd_pcm_hw_params_get_sbits(hw_params);
      if (bits != fmtBits)
      {
        /* if we opened in 32bit and only have 24bits, pack into 24 */
        if (fmtBits == 32 && bits == 24)
          i = AE_FMT_S24NE4;
        else
          continue;
      }

      /* record that the format fell back to X */
      format.m_dataFormat = i;
      CLog::Log(LOGINFO, "CAESinkALSA::InitializeHW - Using data format %s", CAEUtil::DataFormatToStr(format.m_dataFormat));
      break;
    }

    /* if we failed to find a valid output format */
    if (fmt == SND_PCM_FORMAT_UNKNOWN)
    {
      CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Unable to find a suitable output format");
      return false;
    }
  }

  snd_pcm_uframes_t periodSize, bufferSize;
  snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize);
  snd_pcm_hw_params_get_period_size_max(hw_params, &periodSize, NULL);

  /* 
   We want to make sure, that we have max 200 ms Buffer with 
   a periodSize of approx 50 ms. Choosing a higher bufferSize
   will cause problems with menu sounds. Buffer will be increased
   after those are fixed.
  */
  periodSize  = std::min(periodSize, (snd_pcm_uframes_t) sampleRate / 20);
  bufferSize  = std::min(bufferSize, (snd_pcm_uframes_t) sampleRate / 5);
  
  /* 
   According to upstream we should set buffer size first - so make sure it is always at least
   4x period size to not get underruns (some systems seem to have issues with only 2 periods)
  */
  periodSize = std::min(periodSize, bufferSize / 4);

  CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, bufferSize %lu", periodSize, bufferSize);

  snd_pcm_hw_params_t *hw_params_copy;
  snd_pcm_hw_params_alloca(&hw_params_copy);
  snd_pcm_hw_params_copy(hw_params_copy, hw_params); // copy what we have and is already working

  // Make sure to not initialize too large to not cause underruns
  snd_pcm_uframes_t periodSizeMax = bufferSize / 3;
  if(snd_pcm_hw_params_set_period_size_max(m_pcm, hw_params_copy, &periodSizeMax, NULL) != 0)
  {
    snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy
    CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: Failed to limit periodSize to %lu", periodSizeMax);
  }
  
  // first trying bufferSize, PeriodSize
  // for more info see here:
  // http://mailman.alsa-project.org/pipermail/alsa-devel/2009-September/021069.html
  // the last three tries are done as within pulseaudio

  // backup periodSize and bufferSize first. Restore them after every failed try
  snd_pcm_uframes_t periodSizeTemp, bufferSizeTemp;
  periodSizeTemp = periodSize;
  bufferSizeTemp = bufferSize;
  if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
    || snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0
    || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
  {
    bufferSize = bufferSizeTemp;
    periodSize = periodSizeTemp;
    // retry with PeriodSize, bufferSize
    snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy
    if (snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0
      || snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
      || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
    {
      // try only periodSize
      periodSize = periodSizeTemp;
      snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy
      if(snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0 
        || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
      {
        // try only BufferSize
        bufferSize = bufferSizeTemp;
        snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restory working copy
        if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
          || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
        {
          // set default that Alsa would choose
          CLog::Log(LOGWARNING, "CAESinkAlsa::IntializeHW - Using default alsa values - set failed");
          if (snd_pcm_hw_params(m_pcm, hw_params) != 0)
          {
            CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Could not init a valid sink");
            return false;
          }
        }
      }
      // reread values when alsa default was kept
      snd_pcm_get_params(m_pcm, &bufferSize, &periodSize);
    }
  }
  
  CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, bufferSize %lu", periodSize, bufferSize);

  /* set the format parameters */
  format.m_sampleRate   = sampleRate;
  format.m_frames       = periodSize;
  format.m_frameSamples = periodSize * format.m_channelLayout.Count();
  format.m_frameSize    = snd_pcm_frames_to_bytes(m_pcm, 1);

  m_bufferSize = (unsigned int)bufferSize;
  m_timeout    = std::ceil((double)(bufferSize * 1000) / (double)sampleRate);

  CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Setting timeout to %d ms", m_timeout);

  return true;
}
Exemplo n.º 26
0
bool DevAlsa::start(QString *err)
{
#ifdef ALSA
  snd_pcm_hw_params_t *hwparams;
  snd_pcm_sw_params_t *swparams;
  int dir;
  int aerr;
  pthread_attr_t pthread_attr;

  if(snd_pcm_open(&alsa_pcm,alsa_device.toUtf8(),
		  SND_PCM_STREAM_PLAYBACK,0)!=0) {
    *err=tr("unable to open ALSA device")+" \""+alsa_device+"\"";
    return false;
  }
  snd_pcm_hw_params_alloca(&hwparams);
  snd_pcm_hw_params_any(alsa_pcm,hwparams);

  //
  // Access Type
  //
  if(snd_pcm_hw_params_test_access(alsa_pcm,hwparams,
				   SND_PCM_ACCESS_RW_INTERLEAVED)<0) {
    *err=tr("interleaved access not supported");
    return false;
  }
  snd_pcm_hw_params_set_access(alsa_pcm,hwparams,SND_PCM_ACCESS_RW_INTERLEAVED);

  //
  // Sample Format
  //
  if(snd_pcm_hw_params_set_format(alsa_pcm,hwparams,
				  SND_PCM_FORMAT_S32_LE)==0) {
    alsa_format=AudioDevice::S32_LE;
    if(global_log_verbose) {
      Log(LOG_INFO,"using ALSA S32_LE sample format");
    }
  }
  else {
    if(snd_pcm_hw_params_set_format(alsa_pcm,hwparams,
				    SND_PCM_FORMAT_S16_LE)==0) {
      alsa_format=AudioDevice::S16_LE;
      if(global_log_verbose) {
	Log(LOG_INFO,"using ALSA S16_LE sample format");
      }
    }
    else {
      *err=tr("incompatible sample format");
      return false;
    }
  }

  //
  // Sample Rate
  //
  alsa_samplerate=codec()->samplerate();
  snd_pcm_hw_params_set_rate_near(alsa_pcm,hwparams,&alsa_samplerate,&dir);
  if(alsa_samplerate!=codec()->samplerate()) {
    if(global_log_verbose) {
      Log(LOG_INFO,
	  QString().sprintf("using ALSA sample rate of %u samples/sec",
			    alsa_samplerate));
    }
  }

  //
  // Channels
  //
  alsa_channels=codec()->channels();
  snd_pcm_hw_params_set_channels_near(alsa_pcm,hwparams,&alsa_channels);
  if(alsa_channels!=codec()->channels()) {
    if(global_log_verbose) {
      Log(LOG_INFO,
	  QString().sprintf("using ALSA channel count of %u",alsa_channels));
    }
  }

  //
  // Buffer Parameters
  //
  alsa_period_quantity=ALSA_PERIOD_QUANTITY;
  snd_pcm_hw_params_set_periods_near(alsa_pcm,hwparams,&alsa_period_quantity,
				     &dir);
  if(alsa_period_quantity!=ALSA_PERIOD_QUANTITY) {
    if(global_log_verbose) {
      Log(LOG_INFO,
	  QString().sprintf("using ALSA period quantity of %u",
			    alsa_period_quantity));
    }
  }
  alsa_buffer_size=alsa_samplerate/2;
  snd_pcm_hw_params_set_buffer_size_near(alsa_pcm,hwparams,&alsa_buffer_size);
  if(alsa_buffer_size!=(alsa_samplerate/2)) {
    if(global_log_verbose) {
      Log(LOG_INFO,
	  QString().sprintf("using ALSA buffer size of %lu frames",
			    alsa_buffer_size));
    }
  }

  //
  // Fire It Up
  //
  if((aerr=snd_pcm_hw_params(alsa_pcm,hwparams))<0) {
    *err=tr("ALSA device error 1")+": "+snd_strerror(aerr);
    return false;
  }
  alsa_pcm_buffer=new float[alsa_buffer_size*alsa_channels];

  //
  // Set Wake-up Timing
  //
  snd_pcm_sw_params_alloca(&swparams);
  snd_pcm_sw_params_current(alsa_pcm,swparams);
  snd_pcm_sw_params_set_avail_min(alsa_pcm,swparams,alsa_buffer_size/2);
  if((aerr=snd_pcm_sw_params(alsa_pcm,swparams))<0) {
    *err=tr("ALSA device error 2")+": "+snd_strerror(aerr);
    return false;
  }

  //
  // Start the Callback
  //
  pthread_attr_init(&pthread_attr);

//  if(use_realtime) {
//    pthread_attr_setschedpolicy(&pthread_attr,SCHED_FIFO);

  pthread_create(&alsa_pthread,&pthread_attr,AlsaCallback,this);

  //  alsa_meter_timer->start(AUDIO_METER_INTERVAL);

  alsa_play_position_timer->start(50);
  alsa_meter_timer->start(AUDIO_METER_INTERVAL);

  return true;
#else
  return false;
#endif  // ALSA
}
static int drvHostALSAAudioOpen(bool fIn,
                                PALSAAUDIOSTREAMCFG pCfgReq,
                                PALSAAUDIOSTREAMCFG pCfgObt,
                                snd_pcm_t **pphPCM)
{
    snd_pcm_t *phPCM = NULL;
    int rc;

    unsigned int cChannels = pCfgReq->nchannels;
    unsigned int uFreq = pCfgReq->freq;
    snd_pcm_uframes_t obt_buffer_size;

    do
    {
        const char *pszDev = fIn ? s_ALSAConf.pcm_name_in : s_ALSAConf.pcm_name_out;
        if (!pszDev)
        {
            LogRel(("ALSA: Invalid or no %s device name set\n",
                    fIn ? "input" : "output"));
            rc = VERR_INVALID_PARAMETER;
            break;
        }

        int err = snd_pcm_open(&phPCM, pszDev,
                               fIn ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
                               SND_PCM_NONBLOCK);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to open \"%s\" as %s: %s\n", pszDev,
                    fIn ? "ADC" : "DAC", snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        snd_pcm_hw_params_t *pHWParms;
        snd_pcm_hw_params_alloca(&pHWParms); /** @todo Check for successful allocation? */
        err = snd_pcm_hw_params_any(phPCM, pHWParms);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to initialize hardware parameters: %s\n",
                    snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_set_access(phPCM, pHWParms,
                                           SND_PCM_ACCESS_RW_INTERLEAVED);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to set access type: %s\n", snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_set_format(phPCM, pHWParms, pCfgReq->fmt);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to set audio format to %d: %s\n",
                    pCfgReq->fmt, snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_set_rate_near(phPCM, pHWParms, &uFreq, 0);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to set frequency to %dHz: %s\n",
                    pCfgReq->freq, snd_strerror(err)));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_set_channels_near(phPCM, pHWParms, &cChannels);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to set number of channels to %d\n", pCfgReq->nchannels));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        if (   cChannels != 1
            && cChannels != 2)
        {
            LogRel(("ALSA: Number of audio channels (%u) not supported\n", cChannels));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        unsigned int period_size = pCfgReq->period_size;
        unsigned int buffer_size = pCfgReq->buffer_size;

        if (   !((fIn && s_ALSAConf.size_in_usec_in)
            ||  (!fIn && s_ALSAConf.size_in_usec_out)))
        {
            if (!buffer_size)
            {
                buffer_size = DEFAULT_BUFFER_SIZE;
                period_size = DEFAULT_PERIOD_SIZE;
            }
        }

        if (buffer_size)
        {
            if (   ( fIn && s_ALSAConf.size_in_usec_in)
                || (!fIn && s_ALSAConf.size_in_usec_out))
            {
                if (period_size)
                {
                    err = snd_pcm_hw_params_set_period_time_near(phPCM, pHWParms,
                                                                 &period_size, 0);
                    if (err < 0)
                    {
                        LogRel(("ALSA: Failed to set period time %d\n", pCfgReq->period_size));
                        rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                        break;
                    }
                }

                err = snd_pcm_hw_params_set_buffer_time_near(phPCM, pHWParms,
                                                             &buffer_size, 0);
                if (err < 0)
                {
                    LogRel(("ALSA: Failed to set buffer time %d\n", pCfgReq->buffer_size));
                    rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                    break;
                }
            }
            else
            {
                snd_pcm_uframes_t period_size_f = (snd_pcm_uframes_t)period_size;
                snd_pcm_uframes_t buffer_size_f = (snd_pcm_uframes_t)buffer_size;

                snd_pcm_uframes_t minval;

                if (period_size_f)
                {
                    minval = period_size_f;

                    int dir = 0;
                    err = snd_pcm_hw_params_get_period_size_min(pHWParms,
                                                                &minval, &dir);
                    if (err < 0)
                    {
                        LogRel(("ALSA: Could not determine minimal period size\n"));
                        rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                        break;
                    }
                    else
                    {
                        LogFunc(("Minimal period size is: %ld\n", minval));
                        if (period_size_f < minval)
                        {
                            if (   ( fIn && s_ALSAConf.period_size_in_overriden)
                                || (!fIn && s_ALSAConf.period_size_out_overriden))
                            {
                                LogFunc(("Period size %RU32 is less than minimal period size %RU32\n",
                                         period_size_f, minval));
                            }

                            period_size_f = minval;
                        }
                    }

                    err = snd_pcm_hw_params_set_period_size_near(phPCM, pHWParms,
                                                                 &period_size_f, 0);
                    LogFunc(("Period size is: %RU32\n", period_size_f));
                    if (err < 0)
                    {
                        LogRel(("ALSA: Failed to set period size %d (%s)\n",
                                period_size_f, snd_strerror(err)));
                        rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                        break;
                    }
                }

                /* Calculate default buffer size here since it might have been changed
                 * in the _near functions */
                buffer_size_f = 4 * period_size_f;

                minval = buffer_size_f;
                err = snd_pcm_hw_params_get_buffer_size_min(pHWParms, &minval);
                if (err < 0)
                {
                    LogRel(("ALSA: Could not retrieve minimal buffer size\n"));
                    rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                    break;
                }
                else
                {
                    LogFunc(("Minimal buffer size is: %RU32\n", minval));
                    if (buffer_size_f < minval)
                    {
                        if (   ( fIn && s_ALSAConf.buffer_size_in_overriden)
                            || (!fIn && s_ALSAConf.buffer_size_out_overriden))
                        {
                            LogFunc(("Buffer size %RU32 is less than minimal buffer size %RU32\n",
                                     buffer_size_f, minval));
                        }

                        buffer_size_f = minval;
                    }
                }

                err = snd_pcm_hw_params_set_buffer_size_near(phPCM,
                                                             pHWParms, &buffer_size_f);
                LogFunc(("Buffer size is: %RU32\n", buffer_size_f));
                if (err < 0)
                {
                    LogRel(("ALSA: Failed to set buffer size %d: %s\n",
                            buffer_size_f, snd_strerror(err)));
                    rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
                    break;
                }
            }
        }
        else
            LogFunc(("Warning: Buffer size is not set\n"));

        err = snd_pcm_hw_params(phPCM, pHWParms);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to apply audio parameters\n"));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        err = snd_pcm_hw_params_get_buffer_size(pHWParms, &obt_buffer_size);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to get buffer size\n"));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        snd_pcm_uframes_t obt_period_size;
        int dir = 0;
        err = snd_pcm_hw_params_get_period_size(pHWParms, &obt_period_size, &dir);
        if (err < 0)
        {
            LogRel(("ALSA: Failed to get period size\n"));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        LogFunc(("Freq=%dHz, period size=%RU32, buffer size=%RU32\n",
                 pCfgReq->freq, obt_period_size, obt_buffer_size));

        err = snd_pcm_prepare(phPCM);
        if (err < 0)
        {
            LogRel(("ALSA: Could not prepare hPCM %p\n", (void *)phPCM));
            rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */
            break;
        }

        if (   !fIn
            && s_ALSAConf.threshold)
        {
            unsigned uShift;
            rc = drvHostALSAAudioALSAGetShift(pCfgReq->fmt, &uShift);
            if (RT_SUCCESS(rc))
            {
                int bytes_per_sec = uFreq
                    << (cChannels == 2)
                    << uShift;

                snd_pcm_uframes_t threshold
                    = (s_ALSAConf.threshold * bytes_per_sec) / 1000;

                rc = drvHostALSAAudioSetThreshold(phPCM, threshold);
            }
        }
        else
            rc = VINF_SUCCESS;
    }
    while (0);

    if (RT_SUCCESS(rc))
    {
        pCfgObt->fmt       = pCfgReq->fmt;
        pCfgObt->nchannels = cChannels;
        pCfgObt->freq      = uFreq;
        pCfgObt->samples   = obt_buffer_size;

        *pphPCM = phPCM;
    }
    else
        drvHostALSAAudioClose(&phPCM);

    LogFlowFuncLeaveRC(rc);
    return rc;
}
Exemplo n.º 28
0
/*auNew---------------------------------------------------*/
Audio* auAlloc(int sizeofstarself, auAudioCallback_t callback, BOOL isOutput, unsigned numChannels)
{
  Audio* self = (Audio*)calloc(1, sizeofstarself);

  if(self != NULL)
    {
      self->isOutput                     = isOutput;
      self->isPlaying                    = NO;
      self->audioCallback                = callback;
      self->numChannels                  = numChannels;
      self->targetMasterVolume           = 1;
      auSetMasterVolumeSmoothing(self, 0.9999);
      
#if defined __APPLE__
      int i;
      OSStatus error;
      self->dataFormat.mSampleRate       = AU_SAMPLE_RATE;
      self->dataFormat.mBytesPerPacket   = 4 * numChannels  ;
      self->dataFormat.mFramesPerPacket  = 1             ;
      self->dataFormat.mBytesPerFrame    = 4 * numChannels  ;
      self->dataFormat.mBitsPerChannel   = 32            ;
      self->dataFormat.mChannelsPerFrame = numChannels      ;
      self->dataFormat.mFormatID         = kAudioFormatLinearPCM;
      //self->dataFormat.mFormatFlags    = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
      self->dataFormat.mFormatFlags      = kLinearPCMFormatFlagIsFloat;
      
      if(isOutput)
        error = AudioQueueNewOutput(&(self->dataFormat), auAudioOutputCallback, self, NULL, NULL, 0, &(self->queue));
      else
        error = AudioQueueNewInput (&(self->dataFormat), auAudioInputCallback, self, NULL, NULL, 0, &(self->queue));
      if(error) 
        {
          fprintf(stderr, "Audio.c: unable to allocate Audio queue\n"); 
          return auDestroy(self);
        }
      else //(!error)
        {
          unsigned bufferNumBytes = AU_BUFFER_NUM_FRAMES * numChannels * sizeof(auSample_t);
          for(i=0; i<AU_NUM_AUDIO_BUFFERS; i++)
            {
              error = AudioQueueAllocateBuffer(self->queue, bufferNumBytes, &((self->buffers)[i]));
              if(error) 
                {
                  self = auDestroy(self);
                  fprintf(stderr, "Audio.c: allocate buffer error\n");
                  break;
                }
            }
        }
        
#elif defined __linux__
      int error = 0;

      snd_pcm_hw_params_t  *hardwareParameters;
      snd_pcm_hw_params_alloca(&hardwareParameters);

      //untested for input stream...
      const char* name = (isOutput) ? AU_SPEAKER_DEVICE_NAME : AU_MIC_DEVICE_NAME;
      unsigned direction = (isOutput) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE;
      
      error = snd_pcm_open(&(self->device), AU_SPEAKER_DEVICE_NAME, SND_PCM_STREAM_PLAYBACK, 0);
      if(error < 0) fprintf(stderr, "Audio.c: Unable to open speaker device %s: %s\n", AU_SPEAKER_DEVICE_NAME, snd_strerror(error));
            
      if(error >= 0)
        {
          error = snd_pcm_hw_params_any(self->device, hardwareParameters);
            if(error < 0) fprintf(stderr, "Audio.c: Unable to get a generic hardware configuration: %s\n", snd_strerror(error));
        }
      if(error >= 0)
        {
          error = snd_pcm_hw_params_set_access(self->device, hardwareParameters, SND_PCM_ACCESS_RW_INTERLEAVED);
          if(error < 0) fprintf(stderr, "Audio.c: Device does not support interleaved audio access: %s\n", snd_strerror(error));
        }
      if(error >= 0)
        {
          error = snd_pcm_hw_params_set_format(self->device, hardwareParameters, /*SND_PCM_FORMAT_S16*/ SND_PCM_FORMAT_FLOAT) ;
          if(error < 0) fprintf(stderr, "Audio.c: Unable to set sample format: %s\n", snd_strerror(error));
        }
      if(error >= 0)
        {
          //self->numChannels = AU_NUM_CHANNELS;
          error = snd_pcm_hw_params_set_channels_near(self->device, hardwareParameters, &self->numChannels);
          if(error < 0) fprintf(stderr, "Audio.c: unable to set the number of channels to %i: %s\n", self->numChannels, snd_strerror(error));
          else if(self->numChannels != numChannels)
            fprintf(stderr, "Audio.c: device does not support %u numChannels, %i will be used instead\n", numChannels, self->numChannels);  
        }
      if(error >= 0)
        {
          unsigned int sampleRate = AU_SAMPLE_RATE;
          error = snd_pcm_hw_params_set_rate_near(self->device, hardwareParameters, &sampleRate, 0);
          if(error < 0) fprintf(stderr, "Audio.c: Unable to set the sample rate to %u: %s\n", sampleRate, snd_strerror(error));
          else if(sampleRate != AU_SAMPLE_RATE)
            fprintf(stderr, "Audio.c: device does not support %i sample rate, %u will be used instead\n", (int)AU_SAMPLE_RATE, sampleRate);
        }
      if(error >= 0)
        {
          int dir = 0;
          self->bufferNumFrames = AU_BUFFER_NUM_FRAMES; //the buffer I give to ALSA
          error = snd_pcm_hw_params_set_period_size_near(self->device, hardwareParameters, &(self->bufferNumFrames), &dir);
          if(error < 0) fprintf(stderr, "Audio.cpp: Unable to set the sample buffer size to %lu: %s\n", self->bufferNumFrames, snd_strerror(error));
          else if(self->bufferNumFrames != AU_BUFFER_NUM_FRAMES)
            fprintf(stderr, "Audio.c: device does not support %i period size, %lu will be used instead\n", AU_BUFFER_NUM_FRAMES, self->bufferNumFrames);
        }
      if(error >= 0)
        {
          unsigned long int internalBufferNumFrames = self->bufferNumFrames * AU_NUM_AUDIO_BUFFERS; //the buffer ALSA uses internally
          error = snd_pcm_hw_params_set_buffer_size_near(self->device, hardwareParameters, &internalBufferNumFrames);
          if(error < 0) fprintf(stderr, "Audio.c: Unable to set the internal buffer size to %lu: %s\n", internalBufferNumFrames, snd_strerror(error));
          else if(internalBufferNumFrames != AU_NUM_AUDIO_BUFFERS * self->bufferNumFrames)
              fprintf(stderr, "Audio.c: device does not support %lu internal buffer size, %lu will be used instead\n", AU_NUM_AUDIO_BUFFERS * self->bufferNumFrames, internalBufferNumFrames);
        }
      if(error >= 0)
        {
          error = snd_pcm_hw_params(self->device, hardwareParameters);
          if(error < 0) fprintf(stderr, "Audio.c: Unable to load the hardware parameters into the device: %s\n", snd_strerror(error));
        }
      if(error >= 0)
       {
         unsigned int size = sizeof(auSample_t) * self->numChannels * self->bufferNumFrames;
         self->sampleBuffer = (auSample_t*)malloc(size);
         if(self->sampleBuffer == NULL)
           {
              error = -1;
              perror("Audio.c: Unable to allocate audio buffers \n");
           }
       }
      if (error < 0) self = auDestroy(self);
#endif
    }
  else perror("Audio.c: Unable to create new Audio object");
  
  srandom((unsigned)time(NULL));

  return self;
}
Exemplo n.º 29
0
static void rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa)
{
    snd_pcm_hw_params_t* hw_params;
    snd_pcm_sw_params_t* sw_params;
    int error;
    snd_pcm_uframes_t frames;
    snd_pcm_uframes_t start_threshold;

    snd_pcm_drop(alsa->out_handle);

    error = snd_pcm_hw_params_malloc(&hw_params);
    if (error < 0)
    {
        DEBUG_WARN("snd_pcm_hw_params_malloc failed");
        return;
    }
    snd_pcm_hw_params_any(alsa->out_handle, hw_params);
    snd_pcm_hw_params_set_access(alsa->out_handle, hw_params,
                                 SND_PCM_ACCESS_RW_INTERLEAVED);
    snd_pcm_hw_params_set_format(alsa->out_handle, hw_params,
                                 alsa->format);
    snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params,
                                    &alsa->actual_rate, NULL);
    snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params,
                                        &alsa->actual_channels);
    if (alsa->latency < 0)
        frames = alsa->actual_rate * 4; /* Default to 4-second buffer */
    else
        frames = alsa->latency * alsa->actual_rate * 2 / 1000; /* Double of the latency */
    if (frames < alsa->actual_rate / 2)
        frames = alsa->actual_rate / 2; /* Minimum 0.5-second buffer */
    snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params,
                                           &frames);
    snd_pcm_hw_params(alsa->out_handle, hw_params);
    snd_pcm_hw_params_free(hw_params);

    error = snd_pcm_sw_params_malloc(&sw_params);
    if (error < 0)
    {
        DEBUG_WARN("snd_pcm_sw_params_malloc failed");
        return;
    }
    snd_pcm_sw_params_current(alsa->out_handle, sw_params);
    if (alsa->latency == 0)
        start_threshold = 0;
    else
        start_threshold = frames / 2;
    snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, start_threshold);
    snd_pcm_sw_params(alsa->out_handle, sw_params);
    snd_pcm_sw_params_free(sw_params);

    snd_pcm_prepare(alsa->out_handle);

    DEBUG_SVC("hardware buffer %d frames, playback buffer %.2g seconds",
              (int)frames, (double)frames / 2.0 / (double)alsa->actual_rate);
    if ((alsa->actual_rate != alsa->source_rate) ||
            (alsa->actual_channels != alsa->source_channels))
    {
        DEBUG_SVC("actual rate %d / channel %d is different from source rate %d / channel %d, resampling required.",
                  alsa->actual_rate, alsa->actual_channels, alsa->source_rate, alsa->source_channels);
    }
}
Exemplo n.º 30
0
bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle)
{
#define TRY(call, error) do { \
		if (ALSA_CALL(call, error) < 0) \
			return false; \
	} while(0)

    snd_pcm_hw_params_t *hwparams;
    snd_pcm_hw_params_alloca(&hwparams);

    const unsigned SFL_ALSA_PERIOD_SIZE = 160;
    const unsigned SFL_ALSA_NB_PERIOD = 8;
    const unsigned SFL_ALSA_BUFFER_SIZE = SFL_ALSA_PERIOD_SIZE * SFL_ALSA_NB_PERIOD;

    snd_pcm_uframes_t period_size = SFL_ALSA_PERIOD_SIZE;
    snd_pcm_uframes_t buffer_size = SFL_ALSA_BUFFER_SIZE;
    unsigned int periods = SFL_ALSA_NB_PERIOD;

    snd_pcm_uframes_t  period_size_min = 0;
    snd_pcm_uframes_t  period_size_max = 0;
    snd_pcm_uframes_t  buffer_size_min = 0;
    snd_pcm_uframes_t  buffer_size_max = 0;

#define HW pcm_handle, hwparams /* hardware parameters */
    TRY(snd_pcm_hw_params_any(HW), "hwparams init");

    TRY(snd_pcm_hw_params_set_access(HW, SND_PCM_ACCESS_RW_INTERLEAVED), "access type");
    TRY(snd_pcm_hw_params_set_format(HW, SND_PCM_FORMAT_S16_LE), "sample format");

    TRY(snd_pcm_hw_params_set_rate_resample(HW, 0), "hardware sample rate"); /* prevent software resampling */
    TRY(snd_pcm_hw_params_set_rate_near(HW, &audioFormat_.sample_rate, nullptr), "sample rate");

    // TODO: use snd_pcm_query_chmaps or similar to get hardware channel num
    audioFormat_.nb_channels = 2;
    TRY(snd_pcm_hw_params_set_channels_near(HW, &audioFormat_.nb_channels), "channel count");

    snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min);
    snd_pcm_hw_params_get_buffer_size_max(hwparams, &buffer_size_max);
    snd_pcm_hw_params_get_period_size_min(hwparams, &period_size_min, nullptr);
    snd_pcm_hw_params_get_period_size_max(hwparams, &period_size_max, nullptr);
    DEBUG("Buffer size range from %lu to %lu", buffer_size_min, buffer_size_max);
    DEBUG("Period size range from %lu to %lu", period_size_min, period_size_max);
    buffer_size = buffer_size > buffer_size_max ? buffer_size_max : buffer_size;
    buffer_size = buffer_size < buffer_size_min ? buffer_size_min : buffer_size;
    period_size = period_size > period_size_max ? period_size_max : period_size;
    period_size = period_size < period_size_min ? period_size_min : period_size;

    TRY(snd_pcm_hw_params_set_buffer_size_near(HW, &buffer_size), "Unable to set buffer size for playback");
    TRY(snd_pcm_hw_params_set_period_size_near(HW, &period_size, nullptr), "Unable to set period size for playback");
    TRY(snd_pcm_hw_params_set_periods_near(HW, &periods, nullptr), "Unable to set number of periods for playback");
    TRY(snd_pcm_hw_params(HW), "hwparams");

    snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size);
    snd_pcm_hw_params_get_period_size(hwparams, &period_size, nullptr);
    snd_pcm_hw_params_get_rate(hwparams, &audioFormat_.sample_rate, nullptr);
    snd_pcm_hw_params_get_channels(hwparams, &audioFormat_.nb_channels);
    DEBUG("Was set period_size = %lu", period_size);
    DEBUG("Was set buffer_size = %lu", buffer_size);

    if (2 * period_size > buffer_size) {
        ERROR("buffer to small, could not use");
        return false;
    }

#undef HW

    DEBUG("%s using format %s",
          (snd_pcm_stream(pcm_handle) == SND_PCM_STREAM_PLAYBACK) ? "playback" : "capture",
          audioFormat_.toString().c_str() );

    snd_pcm_sw_params_t *swparams = NULL;
    snd_pcm_sw_params_alloca(&swparams);

#define SW pcm_handle, swparams /* software parameters */
    snd_pcm_sw_params_current(SW);
    TRY(snd_pcm_sw_params_set_start_threshold(SW, period_size * 2), "start threshold");
    TRY(snd_pcm_sw_params(SW), "sw parameters");
#undef SW

    return true;

#undef TRY
}