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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/* 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
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; }
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; }
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; }
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"); }
/* 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); }
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(¶ms); 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; }
/** * 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)
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(¶ms)) < 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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
/*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; }
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); } }
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 }