static void init_data(struct linear_priv *data, snd_pcm_format_t src_format, snd_pcm_format_t dst_format) { int src_le, dst_le, src_bytes, dst_bytes; src_bytes = snd_pcm_format_width(src_format) / 8; dst_bytes = snd_pcm_format_width(dst_format) / 8; src_le = snd_pcm_format_little_endian(src_format) > 0; dst_le = snd_pcm_format_little_endian(dst_format) > 0; data->dst_bytes = dst_bytes; data->cvt_endian = src_le != dst_le; data->copy_bytes = src_bytes < dst_bytes ? src_bytes : dst_bytes; if (src_le) { data->copy_ofs = 4 - data->copy_bytes; data->src_ofs = src_bytes - data->copy_bytes; } else data->src_ofs = snd_pcm_format_physical_width(src_format) / 8 - src_bytes; if (dst_le) data->dst_ofs = 4 - data->dst_bytes; else data->dst_ofs = snd_pcm_format_physical_width(dst_format) / 8 - dst_bytes; if (snd_pcm_format_signed(src_format) != snd_pcm_format_signed(dst_format)) { if (dst_le) data->flip = (__force u32)cpu_to_le32(0x80000000); else data->flip = (__force u32)cpu_to_be32(0x80000000); } }
static void share_areas(snd_pcm_direct_t *dshare, const snd_pcm_channel_area_t *src_areas, const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t src_ofs, snd_pcm_uframes_t dst_ofs, snd_pcm_uframes_t size) { unsigned int chn, dchn, channels; snd_pcm_format_t format; channels = dshare->channels; format = dshare->shmptr->s.format; if (dshare->interleaved) { unsigned int fbytes = snd_pcm_format_physical_width(format) / 8; memcpy(((char *)dst_areas[0].addr) + (dst_ofs * channels * fbytes), ((char *)src_areas[0].addr) + (src_ofs * channels * fbytes), size * channels * fbytes); } else { for (chn = 0; chn < channels; chn++) { dchn = dshare->bindings ? dshare->bindings[chn] : chn; snd_pcm_area_copy(&dst_areas[dchn], dst_ofs, &src_areas[chn], src_ofs, size, format); } } }
/********************************************************************************** * pcm_init() * ***********************************************************************************/ static void pcm_init(void) { int err; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { printf("Playback open error: %s\n", snd_strerror(err)); } if ((err = set_hwparams(handle, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { printf("Setting of hwparams failed: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } if ((err = set_swparams(handle, swparams)) < 0) { printf("Setting of swparams failed: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } /*分配空间 period的空间,period指向空间首地址*/ period_size_real = period_size * channels * snd_pcm_format_physical_width(format) / 8;//snd_pcm_format_physical_width:return bits needed to store a PCM sample. period = malloc(period_size_real); if (period == NULL) { printf("No enough memory\n"); exit(EXIT_FAILURE); } fprintf(stdout,"pcm_init sucess !\n"); }
static int saarb_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int width = snd_pcm_format_physical_width(params_format(params)); int ret; ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0, PM860X_CLK_DIR_OUT); if (ret < 0) return ret; ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT); if (ret < 0) return ret; ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); if (ret < 0) return ret; ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width); return ret; }
int snd_pcm_plugin_build_copy(struct snd_pcm_substream *plug, struct snd_pcm_plugin_format *src_format, struct snd_pcm_plugin_format *dst_format, struct snd_pcm_plugin **r_plugin) { int err; struct snd_pcm_plugin *plugin; int width; snd_assert(r_plugin != NULL, return -ENXIO); *r_plugin = NULL; snd_assert(src_format->format == dst_format->format, return -ENXIO); snd_assert(src_format->rate == dst_format->rate, return -ENXIO); snd_assert(src_format->channels == dst_format->channels, return -ENXIO); width = snd_pcm_format_physical_width(src_format->format); snd_assert(width > 0, return -ENXIO); err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format, 0, &plugin); if (err < 0) return err; plugin->transfer = copy_transfer; *r_plugin = plugin; return 0; }
int snd_pcm_area_silence(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset, unsigned int samples, snd_pcm_format_t format) { char *dst; unsigned int dst_step; int width; if (!dst_area->addr) return 0; width = snd_pcm_format_physical_width(format); if (width < 8) return area_silence_4bit(dst_area, dst_offset, samples, format); dst = snd_pcm_channel_area_addr(dst_area, dst_offset); if (dst_area->step == (unsigned int) width) { snd_pcm_format_set_silence(format, dst, samples); return 0; } dst_step = dst_area->step / 8; while (samples-- > 0) { snd_pcm_format_set_silence(format, dst, 1); dst += dst_step; } return 0; }
int snd_pcm_plugin_build_copy(struct snd_pcm_substream *plug, struct snd_pcm_plugin_format *src_format, struct snd_pcm_plugin_format *dst_format, struct snd_pcm_plugin **r_plugin) { int err; struct snd_pcm_plugin *plugin; int width; if (snd_BUG_ON(!r_plugin)) return -ENXIO; *r_plugin = NULL; if (snd_BUG_ON(src_format->format != dst_format->format)) return -ENXIO; if (snd_BUG_ON(src_format->rate != dst_format->rate)) return -ENXIO; if (snd_BUG_ON(src_format->channels != dst_format->channels)) return -ENXIO; width = snd_pcm_format_physical_width(src_format->format); if (snd_BUG_ON(width <= 0)) return -ENXIO; err = snd_pcm_plugin_build(plug, "copy", src_format, dst_format, 0, &plugin); if (err < 0) return err; plugin->transfer = copy_transfer; *r_plugin = plugin; return 0; }
int snd_pcm_linear_get_index(snd_pcm_format_t src_format, snd_pcm_format_t dst_format) { int sign, width, pwidth, endian; sign = (snd_pcm_format_signed(src_format) != snd_pcm_format_signed(dst_format)); #ifdef SND_LITTLE_ENDIAN endian = snd_pcm_format_big_endian(src_format); #else endian = snd_pcm_format_little_endian(src_format); #endif if (endian < 0) endian = 0; pwidth = snd_pcm_format_physical_width(src_format); width = snd_pcm_format_width(src_format); if (pwidth == 24) { switch (width) { case 24: width = 0; break; case 20: width = 1; break; case 18: default: width = 2; break; } return width * 4 + endian * 2 + sign + 16; } else { width = width / 8 - 1; return width * 4 + endian * 2 + sign; } }
/** * \brief Set stream format * \param pcm ordinary PCM handle * \param rate requested channels * \param used_rate returned real channels * \return 0 on success otherwise a negative error code */ int sndo_pcm_param_format(sndo_pcm_t *pcm, snd_pcm_format_t format, snd_pcm_subformat_t subformat) { int err; if (subformat != SND_PCM_SUBFORMAT_STD) return -EINVAL; err = snd_pcm_format_physical_width(format); if (err < 0) return err; if (err % 8) return -EINVAL; err = sndo_pcm_setup(pcm); if (err < 0) return err; if (pcm->playback) { err = snd_pcm_hw_params_set_format(pcm->capture, pcm->p_hw_params, format); if (err < 0) { SNDERR("cannot set requested format for the playback direction"); return err; } } if (pcm->capture) { err = snd_pcm_hw_params_set_format(pcm->capture, pcm->c_hw_params, format); if (err < 0) { SNDERR("cannot set requested format for the capture direction"); return err; } } return 0; }
static void play_callback(snd_async_handler_t *ahandler) { snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); int err; signed short *samples_buf; samples_buf = malloc((period_size * channels * snd_pcm_format_physical_width(format)) / 8); if(file_capture == 0) { printf("err file\r\n"); } struct timeval oldtv; struct timeval tv; /*avasounil = snd_pcm_avail_update(handle);*/ if ((err = snd_pcm_readi (handle, samples_buf,period_size)) != period_size) { fprintf (stderr, "read from audio interface failed (%s)\n",snd_strerror (err)); exit (1); } else { gettimeofday(&tv,NULL); printf("time %lu\n",(tv.tv_sec-oldtv.tv_sec)*1000000+tv.tv_usec-oldtv.tv_usec); oldtv = tv; fwrite(samples_buf,2,910,file_capture); } }
static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; unsigned int pll_out = 0; unsigned int wm9713_div = 0; int ret = 0; int rate = params_rate(params); int width = snd_pcm_format_physical_width(params_format(params)); /* Only support ratios that we can generate neatly from the AC97 * based master clock - in particular, this excludes 44.1kHz. * In most applications the voice DAC will be used for telephony * data so multiples of 8kHz will be the common case. */ switch (rate) { case 8000: wm9713_div = 12; break; case 16000: wm9713_div = 6; break; case 48000: wm9713_div = 2; break; default: /* Don't support OSS emulation */ return -EINVAL; } /* Add 1 to the width for the leading clock cycle */ pll_out = rate * (width + 1) * 8; ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1); if (ret < 0) return ret; ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out); if (ret < 0) return ret; if (clk_pout) ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV, WM9713_PCMDIV(wm9713_div)); else ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV, WM9713_PCMDIV(wm9713_div)); if (ret < 0) return ret; return 0; }
static struct snd_format* snd_format_alloc(int rate, int channels) { struct snd_format* f = malloc(sizeof(struct snd_format)); f->format = SND_PCM_FORMAT_S16_BE; f->rate = rate; f->channels = channels; f->sample_bits = snd_pcm_format_physical_width(f->format); f->bps = (rate * f->sample_bits * channels) >> 3; return f; }
static int snd_rpi_iqaudio_dac_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; // NOT USED struct snd_soc_dai *codec_dai = rtd->codec_dai; // NOT USED struct snd_soc_codec *codec = rtd->codec; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; unsigned int sample_bits = snd_pcm_format_physical_width(params_format(params)); return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); }
static void set_params(void) { hwparams.format=SND_PCM_FORMAT_S16_LE; hwparams.channels=2; hwparams.rate=44100; snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); snd_pcm_hw_params_any(handle, params); snd_pcm_hw_params_set_format(handle, params, hwparams.format); snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0); buffer_time=0; snd_pcm_hw_params_get_buffer_time_max(params,&buffer_time, 0); period_time=125000; snd_pcm_hw_params_set_period_time_near(handle, params,&period_time, 0); buffer_time = 500000; snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); /*monotonic = */snd_pcm_hw_params_is_monotonic(params); /*can_pause = */snd_pcm_hw_params_can_pause(params); printf("sizeof(params) : %d\n",sizeof(params)); snd_pcm_hw_params(handle, params); snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); size_t n=chunk_size; snd_pcm_sw_params_set_avail_min(handle, swparams, n); snd_pcm_uframes_t start_threshold, stop_threshold; start_threshold=22050; snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); stop_threshold=22050; snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); snd_pcm_format_physical_width(hwparams.format); }
static int snd_pcm_plugin_alloc(snd_pcm_plugin_t *plugin, snd_pcm_uframes_t frames) { snd_pcm_plugin_format_t *format; ssize_t width; size_t size; unsigned int channel; snd_pcm_plugin_channel_t *c; if (plugin->stream == SNDRV_PCM_STREAM_PLAYBACK) { format = &plugin->src_format; } else { format = &plugin->dst_format; } if ((width = snd_pcm_format_physical_width(format->format)) < 0) return width; size = frames * format->channels * width; snd_assert((size % 8) == 0, return -ENXIO); size /= 8; if (plugin->buf_frames < frames) { if (plugin->buf) vfree(plugin->buf); plugin->buf = vmalloc(size); plugin->buf_frames = frames; } if (!plugin->buf) { plugin->buf_frames = 0; return -ENOMEM; } c = plugin->buf_channels; if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { for (channel = 0; channel < format->channels; channel++, c++) { c->frames = frames; c->enabled = 1; c->wanted = 0; c->area.addr = plugin->buf; c->area.first = channel * width; c->area.step = format->channels * width; } } else if (plugin->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) { snd_assert((size % format->channels) == 0,); size /= format->channels; for (channel = 0; channel < format->channels; channel++, c++) { c->frames = frames; c->enabled = 1; c->wanted = 0; c->area.addr = plugin->buf + (channel * size); c->area.first = 0; c->area.step = width; } } else
static int a2dp_params(snd_pcm_ioplug_t * io, snd_pcm_hw_params_t * params) { snd_pcm_a2dp_t *a2dp = io->private_data; unsigned int period_bytes; a2dp->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8; period_bytes = io->period_size * a2dp->frame_bytes; // DBG("format %s rate %d channels %d", snd_pcm_format_name(io->format), io->rate, io->channels); // DBG("frame_bytes %d period_bytes %d period_size %ld buffer_size %ld", a2dp->frame_bytes, period_bytes, io->period_size, io->buffer_size); return 0; }
/* sDMA supports only 1, 2, and 4 byte transfer elements. */ static void omap_pcm_limit_supported_formats(void) { int i; for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { switch (snd_pcm_format_physical_width(i)) { case 8: case 16: case 32: omap_pcm_hardware.formats |= (1LL << i); break; default: break; } } }
static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock( struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai) { struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai); struct ssc_device *ssc = ssc_p->ssc; struct ssc_clock_data cd; unsigned int rate, width_bits, channels; unsigned int bitrate, ssc_div; unsigned actual_rate; /* * Figure out required bitrate */ rate = params_rate(params); channels = params_channels(params); width_bits = snd_pcm_format_physical_width(params_format(params)); bitrate = rate * width_bits * channels; /* * Figure out required SSC divider and period for required bitrate */ cd.ssc_rate = clk_get_rate(ssc->clk); ssc_div = cd.ssc_rate / bitrate; cd.cmr_div = ssc_div / 2; if (ssc_div & 1) { /* round cmr_div up */ cd.cmr_div++; } cd.period = width_bits - 1; /* * Find actual rate, compare to requested rate */ actual_rate = (cd.ssc_rate / (cd.cmr_div * 2)) / (2 * (cd.period + 1)); pr_debug("playpaq_wm8510: Request rate = %u, actual rate = %u\n", rate, actual_rate); return cd; }
int snd_pcm_area_copy(const snd_pcm_channel_area_t *dst_area, snd_pcm_uframes_t dst_offset, const snd_pcm_channel_area_t *src_area, snd_pcm_uframes_t src_offset, unsigned int samples, snd_pcm_format_t format) { const char *src; char *dst; int width; int src_step, dst_step; if (!dst_area->addr) return 0; if (dst_area == src_area && dst_offset == src_offset) return 0; if (!src_area->addr) return snd_pcm_area_silence(dst_area, dst_offset, samples, format); width = snd_pcm_format_physical_width(format); if (width < 8) return area_copy_4bit(dst_area, dst_offset, src_area, src_offset, samples, format); src = snd_pcm_channel_area_addr(src_area, src_offset); dst = snd_pcm_channel_area_addr(dst_area, dst_offset); if (src_area->step == (unsigned int) width && dst_area->step == (unsigned int) width) { memcpy(dst, src, samples * width / 8); return 0; } src_step = src_area->step / 8; dst_step = dst_area->step / 8; width /= 8; while (samples-- > 0) { memcpy(dst, src, width); src += src_step; dst += dst_step; } return 0; }
int snd_pcm_areas_copy(const snd_pcm_channel_area_t *dst_areas, snd_pcm_uframes_t dst_offset, const snd_pcm_channel_area_t *src_areas, snd_pcm_uframes_t src_offset, unsigned int channels, snd_pcm_uframes_t frames, snd_pcm_format_t format) { int width; if (!channels) return -EINVAL; if (!frames) return -EINVAL; width = snd_pcm_format_physical_width(format); while (channels > 0) { snd_pcm_area_copy(dst_areas, dst_offset, src_areas, src_offset, frames, format); src_areas++; dst_areas++; channels--; } return 0; }
// returns 1 if successful // enc: 0 for PCM, 1 for ULAW, 2 for ALAW (see DirectAudio.h) int getFormatFromAlsaFormat(snd_pcm_format_t alsaFormat, int* sampleSizeInBytes, int* significantBits, int* isSigned, int* isBigEndian, int* enc) { *sampleSizeInBytes = (snd_pcm_format_physical_width(alsaFormat) + 7) / 8; *significantBits = snd_pcm_format_width(alsaFormat); // defaults *enc = 0; // PCM *isSigned = (snd_pcm_format_signed(alsaFormat) > 0); *isBigEndian = (snd_pcm_format_big_endian(alsaFormat) > 0); // non-PCM formats if (alsaFormat == SND_PCM_FORMAT_MU_LAW) { // Mu-Law *sampleSizeInBytes = 8; *enc = 1; *significantBits = *sampleSizeInBytes; } else if (alsaFormat == SND_PCM_FORMAT_A_LAW) { // A-Law *sampleSizeInBytes = 8; *enc = 2; *significantBits = *sampleSizeInBytes; } else if (snd_pcm_format_linear(alsaFormat) < 1) { return 0; } return (*sampleSizeInBytes > 0); }
/* * Set the SSP audio DMA parameters and sample size. * Can be called multiple times by oss emulation. */ static int pxa3xx_ssp_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai * dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct ssp_device *ssp = cpu_dai->private_data; struct pxa3xx_pcm_dma_params *pcm; u32 sscr0, sspsp; u32 width; pcm = kmalloc(sizeof(struct pxa3xx_pcm_dma_params), GFP_KERNEL); if (pcm == NULL) return -ENOMEM; /* bit size */ switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: sscr0 = __raw_readl(ssp->mmio_base + SSCR0); sscr0 |= SSCR0_DataSize(16); __raw_writel(sscr0, ssp->mmio_base + SSCR0); if ((sscr0 & SSCR0_FPCKE ) || (sscr0 & SSCR0_EDSS)) width = DCMD_WIDTH4; else width = DCMD_WIDTH2; break; case SNDRV_PCM_FORMAT_S32_LE: sscr0 = __raw_readl(ssp->mmio_base + SSCR0); sscr0 |= SSCR0_EDSS | SSCR0_DataSize(16); __raw_writel(sscr0, ssp->mmio_base + SSCR0); width = DCMD_WIDTH4; break; default: return -EINVAL; } if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { pcm->name = ssp_names[cpu_dai->id][0]; pcm->dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG; pcm->drcmr = &DRCMR(ssp->drcmr_tx); pcm->dev_addr = ssp->phys_base + SSDR; } else { pcm->name = ssp_names[cpu_dai->id][1]; pcm->dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC; pcm->drcmr = &DRCMR(ssp->drcmr_rx); pcm->dev_addr = ssp->phys_base + SSDR; } pcm->dcmd |= DCMD_BURST16 | width; kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); snd_soc_dai_set_dma_data(cpu_dai, substream, pcm); if (ssp_clk[cpu_dai->id].dai_fmt == SND_SOC_DAIFMT_I2S) { int sfrmwidth = snd_pcm_format_physical_width(params_format(params)); sspsp = __raw_readl(ssp->mmio_base + SSPSP); sspsp |= SSPSP_SFRMWDTH(sfrmwidth); __raw_writel(sspsp, ssp->mmio_base + SSPSP); } return 0; }
int ai_alsa_setup(audio_in_t *ai) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size, period_size; int err; int dir; unsigned int rate; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(ai->alsa.handle, params); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Broken configuration for this PCM: no configurations available.\n"); return -1; } err = snd_pcm_hw_params_set_access(ai->alsa.handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Access type not available.\n"); return -1; } err = snd_pcm_hw_params_set_format(ai->alsa.handle, params, SND_PCM_FORMAT_S16_LE); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Sample format not available.\n"); return -1; } err = snd_pcm_hw_params_set_channels(ai->alsa.handle, params, ai->req_channels); if (err < 0) { snd_pcm_hw_params_get_channels(params, &ai->channels); mp_tmsg(MSGT_TV, MSGL_ERR, "Channel count not available - reverting to default: %d\n", ai->channels); } else { ai->channels = ai->req_channels; } dir = 0; rate = ai->req_samplerate; err = snd_pcm_hw_params_set_rate_near(ai->alsa.handle, params, &rate, &dir); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set samplerate.\n"); } ai->samplerate = rate; dir = 0; ai->alsa.buffer_time = 1000000; err = snd_pcm_hw_params_set_buffer_time_near(ai->alsa.handle, params, &ai->alsa.buffer_time, &dir); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set buffer time.\n"); } dir = 0; ai->alsa.period_time = ai->alsa.buffer_time / 4; err = snd_pcm_hw_params_set_period_time_near(ai->alsa.handle, params, &ai->alsa.period_time, &dir); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Cannot set period time.\n"); } err = snd_pcm_hw_params(ai->alsa.handle, params); if (err < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install hardware parameters: %s", snd_strerror(err)); snd_pcm_hw_params_dump(params, ai->alsa.log); return -1; } dir = -1; snd_pcm_hw_params_get_period_size(params, &period_size, &dir); snd_pcm_hw_params_get_buffer_size(params, &buffer_size); ai->alsa.chunk_size = period_size; if (period_size == buffer_size) { mp_tmsg(MSGT_TV, MSGL_ERR, "Can't use period equal to buffer size (%u == %lu)\n", ai->alsa.chunk_size, (long)buffer_size); return -1; } snd_pcm_sw_params_current(ai->alsa.handle, swparams); err = snd_pcm_sw_params_set_avail_min(ai->alsa.handle, swparams, ai->alsa.chunk_size); err = snd_pcm_sw_params_set_start_threshold(ai->alsa.handle, swparams, 0); err = snd_pcm_sw_params_set_stop_threshold(ai->alsa.handle, swparams, buffer_size); if (snd_pcm_sw_params(ai->alsa.handle, swparams) < 0) { mp_tmsg(MSGT_TV, MSGL_ERR, "Unable to install software parameters:\n"); snd_pcm_sw_params_dump(swparams, ai->alsa.log); return -1; } if (mp_msg_test(MSGT_TV, MSGL_V)) { snd_pcm_dump(ai->alsa.handle, ai->alsa.log); } ai->alsa.bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE); ai->alsa.bits_per_frame = ai->alsa.bits_per_sample * ai->channels; ai->blocksize = ai->alsa.chunk_size * ai->alsa.bits_per_frame / 8; ai->samplesize = ai->alsa.bits_per_sample; ai->bytes_per_sample = ai->alsa.bits_per_sample/8; return 0; }
static void set_params(void) { snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t buffer_size; int err; size_t n; snd_pcm_uframes_t xfer_align; unsigned int rate; snd_pcm_uframes_t start_threshold, stop_threshold; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, params); if (err < 0) { error(_("Broken configuration for this PCM: no configurations available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { error(_("Access type not available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_format(handle, params, hwparams.format); if (err < 0) { error(_("Sample format non available")); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels); if (err < 0) { error(_("Channels count non available")); exit(EXIT_FAILURE); } #if 0 err = snd_pcm_hw_params_set_periods_min(handle, params, 2); assert(err >= 0); #endif rate = hwparams.rate; err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0); assert(err >= 0); if ((float)rate * 1.05 < hwparams.rate || (float)rate * 0.95 > hwparams.rate) { if (!quiet_mode) { char plugex[64]; const char *pcmname = snd_pcm_name(handle); fprintf(stderr, _("Warning: rate is not accurate (requested = %iHz, got = %iHz)\n"), rate, hwparams.rate); if (! pcmname || strchr(snd_pcm_name(handle), ':')) *plugex = 0; else snprintf(plugex, sizeof(plugex), "(-Dplug:%s)", snd_pcm_name(handle)); fprintf(stderr, _(" please, try the plug plugin %s\n"), plugex); } } rate = hwparams.rate; if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0); assert(err >= 0); if (buffer_time > 500000) buffer_time = 500000; } if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near(handle, params, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near(handle, params, &period_frames, 0); assert(err >= 0); if (buffer_time > 0) { err = snd_pcm_hw_params_set_buffer_time_near(handle, params, &buffer_time, 0); } else { err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_frames); } assert(err >= 0); err = snd_pcm_hw_params(handle, params); if (err < 0) { error(_("Unable to install hw params:")); snd_pcm_hw_params_dump(params, log); exit(EXIT_FAILURE); } snd_pcm_hw_params_get_period_size(params, &chunk_size, 0); snd_pcm_hw_params_get_buffer_size(params, &buffer_size); if (chunk_size == buffer_size) { error(_("Can't use period equal to buffer size (%lu == %lu)"), chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align); if (err < 0) { error(_("Unable to obtain xfer align\n")); exit(EXIT_FAILURE); } if (sleep_min) xfer_align = 1; err = snd_pcm_sw_params_set_sleep_min(handle, swparams, sleep_min); assert(err >= 0); if (avail_min < 0) n = chunk_size; else n = (double) rate * avail_min / 1000000; err = snd_pcm_sw_params_set_avail_min(handle, swparams, n); // round up to closest transfer boundary n = (buffer_size / xfer_align) * xfer_align; start_threshold = n; if (start_threshold < 1) start_threshold = 1; if (start_threshold > n) start_threshold = n; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err >= 0); stop_threshold = buffer_size; err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); assert(err >= 0); err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align); assert(err >= 0); if (snd_pcm_sw_params(handle, swparams) < 0) { error(_("unable to install sw params:")); snd_pcm_sw_params_dump(swparams, log); exit(EXIT_FAILURE); } bits_per_sample = snd_pcm_format_physical_width(hwparams.format); bits_per_frame = bits_per_sample * hwparams.channels; chunk_bytes = chunk_size * bits_per_frame / 8; audiobuf = realloc(audiobuf, chunk_bytes); if (audiobuf == NULL) { error(_("not enough memory")); exit(EXIT_FAILURE); } // fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size); }
tmp > io->rate * 1.01 || tmp < io->rate * 0.99) { perror("SNDCTL_DSP_SPEED"); return -EINVAL; } return 0; } static int oss_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params ATTRIBUTE_UNUSED) { snd_pcm_oss_t *oss = io->private_data; int i, tmp, err; unsigned int period_bytes; long oflags, flags; oss->frame_bytes = (snd_pcm_format_physical_width(io->format) * io->channels) / 8; switch (io->format) { case SND_PCM_FORMAT_U8: oss->format = AFMT_U8; break; case SND_PCM_FORMAT_S16_LE: oss->format = AFMT_S16_LE; break; case SND_PCM_FORMAT_S16_BE: oss->format = AFMT_S16_BE; break; default: fprintf(stderr, "*** OSS: unsupported format %s\n", snd_pcm_format_name(io->format)); return -EINVAL; } period_bytes = io->period_size * oss->frame_bytes;
static int aplaypop_open(void) { int err; snd_pcm_t *handle; if (pcm_handle) return 0; snd_pcm_info_t *info; snd_pcm_info_alloca(&info); snd_output_t *log; err = snd_output_stdio_attach(&log, stderr, 0); assert(err == 0); err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0); if (err != 0) { fprintf(stderr, "snd_pcm_open(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_nonblock(handle, 0); if (err != 0) { fprintf(stderr, "snd_pcm_nonblock(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_info(handle, info); if (err != 0) { fprintf(stderr, "snd_pcm_info(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } // DOESN'T WORK! err = snd_pcm_set_params(handle, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, CHANNELS, RATE, 1, 50000); if (err != 0) { fprintf(stderr, "snd_pcm_set_params(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } // RIGHT WAY: snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; unsigned int channels = CHANNELS; unsigned int rate = RATE; snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_hw_params_any(handle, hwparams); if (err != 0) { fprintf(stderr, "Broken configuration for this PCM: %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_access(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_format(handle, hwparams, format); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_format(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_channels(handle, hwparams, channels); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_channels(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, 0); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params_set_rate_near(): %s\n", snd_strerror(err)); exit(EXIT_FAILURE); } /* unsigned buffer_time = 0; snd_pcm_uframes_t buffer_frames = 0; if (buffer_time == 0 && buffer_frames == 0) { err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0); assert(err == 0); if (buffer_time > 500000) buffer_time = 500000; } unsigned period_time = 0; snd_pcm_uframes_t period_frames = 0; if (period_time == 0 && period_frames == 0) { if (buffer_time > 0) period_time = buffer_time / 4; else period_frames = buffer_frames / 4; } if (period_time > 0) err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0); else err = snd_pcm_hw_params_set_period_size_near(handle, hwparams, &period_frames, 0); assert(err == 0); if (buffer_time > 0) err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0); else err = snd_pcm_hw_params_set_buffer_size_near(handle, hwparams, &buffer_frames); assert(err == 0); int monotonic = snd_pcm_hw_params_is_monotonic(hwparams); int can_pause = snd_pcm_hw_params_can_pause(hwparams); */ err = snd_pcm_hw_params(handle, hwparams); if (err != 0) { fprintf(stderr, "snd_pcm_hw_params(): %s\n", snd_strerror(err)); snd_pcm_hw_params_dump(hwparams, log); exit(EXIT_FAILURE); } snd_pcm_uframes_t chunk_size = 0; snd_pcm_hw_params_get_period_size(hwparams, &chunk_size, 0); snd_pcm_uframes_t buffer_size; snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); if (chunk_size == buffer_size) { fprintf(stderr, "Can't use period equal to buffer size (%lu == %lu)", chunk_size, buffer_size); exit(EXIT_FAILURE); } snd_pcm_sw_params_current(handle, swparams); err = snd_pcm_sw_params_set_avail_min(handle, swparams, chunk_size); assert(err == 0); /* round up to closest transfer boundary */ int start_delay = 0; snd_pcm_uframes_t start_threshold; if (start_delay <= 0) start_threshold = buffer_size + (double) rate * start_delay / 1000000; else start_threshold = (double) rate * start_delay / 1000000; start_threshold = start_threshold < 1 ? 1 : start_threshold > buffer_size ? buffer_size : start_threshold; err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold); assert(err == 0); int stop_delay = 0; snd_pcm_uframes_t stop_threshold; if (stop_delay <= 0) stop_threshold = buffer_size + (double) rate * stop_delay / 1000000; else stop_threshold = (double) rate * stop_delay / 1000000; err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold); assert(err == 0); err = snd_pcm_sw_params(handle, swparams); if (err != 0) { fprintf(stderr, "snd_pcm_sw_params(): %s\n", snd_strerror(err)); snd_pcm_sw_params_dump(swparams, log); exit(EXIT_FAILURE); } // END OF THE RIGHT WAY // snd_pcm_dump(handle, log); size_t bits_per_sample = snd_pcm_format_physical_width(format); size_t bits_per_frame = bits_per_sample * channels; size_t chunk_bytes = chunk_size * bits_per_frame / 8; //audiobuf = realloc(audiobuf, chunk_bytes); fprintf(stderr, "%s: %s, Rate %d Hz, Channels=%u\n", snd_pcm_format_name(format), snd_pcm_format_description(format), rate, channels); fprintf(stderr, " bits_per_sample=%u, bits_per_frame=%u, chunk_bytes=%u\n", bits_per_sample, bits_per_frame, chunk_bytes); frame_bytes = bits_per_frame / 8; pcm_handle = handle; return 0; }
int ga_alsa_set_param(struct Xcap_alsa_param *param) { snd_pcm_hw_params_t *hwparams = NULL; snd_pcm_sw_params_t *swparams = NULL; size_t bits_per_sample; unsigned int rate; unsigned int buffer_time = 500000; // in the unit of microsecond unsigned int period_time = 125000; // = buffer_time/4; int monotonic = 0; snd_pcm_uframes_t start_threshold, stop_threshold; int err; // snd_pcm_hw_params_alloca(&hwparams); snd_pcm_sw_params_alloca(&swparams); if((err = snd_pcm_hw_params_any(param->handle, hwparams)) < 0) { ga_error("ALSA: set_param - no configurations available\n"); return -1; } if((err = snd_pcm_hw_params_set_access(param->handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { ga_error("ALSA: set_param - access type (interleaved) not available\n"); return -1; } if((err = snd_pcm_hw_params_set_format(param->handle, hwparams, param->format)) < 0) { ga_error("ALSA: set_param - unsupported sample format.\n"); return -1; } if((err = snd_pcm_hw_params_set_channels(param->handle, hwparams, param->channels)) < 0) { ga_error("ALSA: set_param - channles count not available\n"); return -1; } rate = param->samplerate; if((err = snd_pcm_hw_params_set_rate_near(param->handle, hwparams, &rate, 0)) < 0) { ga_error("ALSA: set_param - set rate failed.\n"); return -1; } if((double)param->samplerate*1.05 < rate || (double)param->samplerate*0.95 > rate) { ga_error("ALSA: set_param/warning - inaccurate rate (req=%iHz, got=%iHz)\n", param->samplerate, rate); } // period_time = buffer_time/4; if((err = snd_pcm_hw_params_set_period_time_near(param->handle, hwparams, &period_time, 0)) < 0) { ga_error("ALSA: set_param - set period time failed.\n"); return -1; } if((err = snd_pcm_hw_params_set_buffer_time_near(param->handle, hwparams, &buffer_time, 0)) < 0) { ga_error("ALSA: set_param - set buffer time failed.\n"); return -1; } // monotonic = snd_pcm_hw_params_is_monotonic(hwparams); if((err = snd_pcm_hw_params(param->handle, hwparams)) < 0) { ga_error("ALSA: set_param - unable to install hw params:"); snd_pcm_hw_params_dump(hwparams, sndlog); return -1; } snd_pcm_hw_params_get_period_size(hwparams, ¶m->chunk_size, 0); snd_pcm_hw_params_get_buffer_size(hwparams, ¶m->buffer_size); if(param->chunk_size == param->buffer_size) { ga_error("ALSA: set_param - cannot use period equal to buffer size (%lu==%lu)\n", param->chunk_size, param->buffer_size); return -1; } // snd_pcm_sw_params_current(param->handle, swparams); err = snd_pcm_sw_params_set_avail_min(param->handle, swparams, param->chunk_size); // start_delay = 1 for capture start_threshold = (double) param->samplerate * /*start_delay=*/ 1 / 1000000; if(start_threshold < 1) start_threshold = 1; if(start_threshold > param->buffer_size) start_threshold = param->buffer_size; if((err = snd_pcm_sw_params_set_start_threshold(param->handle, swparams, start_threshold)) < 0) { ga_error("ALSA: set_param - set start threshold failed.\n"); return -1; } // stop_delay = 0 stop_threshold = param->buffer_size; if((err = snd_pcm_sw_params_set_stop_threshold(param->handle, swparams, stop_threshold)) < 0) { ga_error("ALSA: set_param - set stop threshold failed.\n"); return -1; } // if(snd_pcm_sw_params(param->handle, swparams) < 0) { ga_error("ALSA: set_param - unable to install sw params:"); snd_pcm_sw_params_dump(swparams, sndlog); return -1; } bits_per_sample = snd_pcm_format_physical_width(param->format); if(param->bits_per_sample != bits_per_sample) { ga_error("ALSA: set_param - BPS/HW configuration mismatched %d != %d)\n", param->bits_per_sample, bits_per_sample); } param->bits_per_frame = param->bits_per_sample * param->channels; param->chunk_bytes = param->chunk_size * param->bits_per_frame / 8; return 0; }
static int capture_prepare_params(struct gaudio_snd_dev *snd) { struct snd_pcm_substream *substream = snd->substream; struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_params *params; struct snd_pcm_sw_params *swparams; unsigned long period_size; unsigned long buffer_size; snd_pcm_sframes_t result = 0; snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED; snd->format = SNDRV_PCM_FORMAT_S16_LE; snd->channels = 1; snd->rate = 8000; params = kzalloc(sizeof(*params), GFP_KERNEL); if (!params) { pr_err("Failed to allocate hw params"); return -ENOMEM; } _snd_pcm_hw_params_any(params); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS, snd->access, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT, snd->format, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS, snd->channels, 0); _snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE, snd->rate, 0); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (result < 0) pr_err("SNDRV_PCM_IOCTL_DROP failed: %d\n", (int)result); result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params); if (result < 0) { pr_err("SNDRV_PCM_IOCTL_HW_PARAMS failed: %d\n", (int)result); kfree(params); return result; } result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (result < 0) pr_err("Preparing capture failed: %d\n", (int)result); snd->access = params_access(params); snd->format = params_format(params); snd->channels = params_channels(params); snd->rate = params_rate(params); runtime->frame_bits = snd_pcm_format_physical_width(runtime->format); swparams = kzalloc(sizeof(*swparams), GFP_KERNEL); if (!swparams) { pr_err("Failed to allocate sw params"); kfree(params); return -ENOMEM; } buffer_size = pcm_buffer_size(params); period_size = pcm_period_size(params); swparams->avail_min = period_size/2; swparams->xfer_align = period_size/2; kfree(params); swparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; swparams->period_step = 1; swparams->start_threshold = 1; swparams->stop_threshold = INT_MAX; swparams->silence_size = 0; swparams->silence_threshold = 0; result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, swparams); if (result < 0) pr_err("SNDRV_PCM_IOCTL_SW_PARAMS failed: %d\n", (int)result); kfree(swparams); pr_debug("capture params: access %x, format %x, channels %d, rate %d\n", snd->access, snd->format, snd->channels, snd->rate); return result; }
static int set_snd_pcm_params(struct bat *bat, struct snd_pcm_container *sndpcm) { snd_pcm_format_t format; snd_pcm_hw_params_t *params; unsigned int buffer_time = 0; unsigned int period_time = 0; unsigned int rate; int err; const char *device_name = snd_pcm_name(sndpcm->handle); /* Allocate a hardware parameters object. */ snd_pcm_hw_params_alloca(¶ms); /* Fill it in with default values. */ err = snd_pcm_hw_params_any(sndpcm->handle, params); if (err < 0) { loge(E_SETDEV S_DEFAULT, "%s: %s(%d)", device_name, snd_strerror(err), err); goto fail_exit; } /* Set access mode */ err = snd_pcm_hw_params_set_access(sndpcm->handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { loge(E_SETDEV S_ACCESS, "%s: %s(%d)", device_name, snd_strerror(err), err); goto fail_exit; } /* Set format */ switch (bat->sample_size) { case 1: format = SND_PCM_FORMAT_S8; break; case 2: format = SND_PCM_FORMAT_S16_LE; break; case 3: format = SND_PCM_FORMAT_S24_3LE; break; case 4: format = SND_PCM_FORMAT_S32_LE; break; default: loge(E_PARAMS S_PCMFORMAT, "size=%d", bat->sample_size); goto fail_exit; } err = snd_pcm_hw_params_set_format(sndpcm->handle, params, format); if (err < 0) { loge(E_SETDEV S_PCMFORMAT, "%d %s: %s(%d)", format, device_name, snd_strerror(err), err); goto fail_exit; } /* Set channels */ err = snd_pcm_hw_params_set_channels(sndpcm->handle, params, bat->channels); if (err < 0) { loge(E_SETDEV S_CHANNELS, "%d %s: %s(%d)", bat->channels, device_name, snd_strerror(err), err); goto fail_exit; } /* Set sampling rate */ rate = bat->rate; err = snd_pcm_hw_params_set_rate_near(sndpcm->handle, params, &bat->rate, 0); if (err < 0) { loge(E_SETDEV S_SAMPLERATE, "%d %s: %s(%d)", bat->rate, device_name, snd_strerror(err), err); goto fail_exit; } if ((float) rate * 1.05 < bat->rate || (float) rate * 0.95 > bat->rate) { loge(E_PARAMS S_SAMPLERATE, "requested %dHz, got %dHz", rate, bat->rate); goto fail_exit; } if (snd_pcm_hw_params_get_buffer_time_max(params, &buffer_time, 0) < 0) { loge(E_GETDEV S_BUFFERTIME, "%d %s: %s(%d)", buffer_time, device_name, snd_strerror(err), err); goto fail_exit; } if (buffer_time > 500000) buffer_time = 500000; /* Was 4, changed to 8 to remove reduce capture overrun */ period_time = buffer_time / 8; /* Set buffer time and period time */ err = snd_pcm_hw_params_set_buffer_time_near(sndpcm->handle, params, &buffer_time, 0); if (err < 0) { loge(E_SETDEV S_BUFFERTIME, "%d %s: %s(%d)", buffer_time, device_name, snd_strerror(err), err); goto fail_exit; } err = snd_pcm_hw_params_set_period_time_near(sndpcm->handle, params, &period_time, 0); if (err < 0) { loge(E_SETDEV S_PERIODTIME, "%d %s: %s(%d)", period_time, device_name, snd_strerror(err), err); goto fail_exit; } /* Write the parameters to the driver */ if (snd_pcm_hw_params(sndpcm->handle, params) < 0) { loge(E_SETDEV S_HWPARAMS, "%s: %s(%d)", device_name, snd_strerror(err), err); goto fail_exit; } err = snd_pcm_hw_params_get_period_size(params, &sndpcm->period_size, 0); if (err < 0) { loge(E_GETDEV S_PERIODSIZE, "%zd %s: %s(%d)", sndpcm->period_size, device_name, snd_strerror(err), err); goto fail_exit; } err = snd_pcm_hw_params_get_buffer_size(params, &sndpcm->buffer_size); if (err < 0) { loge(E_GETDEV S_BUFFERSIZE, "%zd %s: %s(%d)", sndpcm->buffer_size, device_name, snd_strerror(err), err); goto fail_exit; } if (sndpcm->period_size == sndpcm->buffer_size) { loge(E_PARAMS, "can't use period equal to buffer size (%zd)", sndpcm->period_size); goto fail_exit; } err = snd_pcm_format_physical_width(format); if (err < 0) { loge(E_PARAMS, "snd_pcm_format_physical_width: %d", err); goto fail_exit; } sndpcm->sample_bits = err; sndpcm->frame_bits = sndpcm->sample_bits * bat->channels; /* Calculate the period bytes */ sndpcm->period_bytes = sndpcm->period_size * sndpcm->frame_bits / 8; sndpcm->buffer = (char *) malloc(sndpcm->period_bytes); if (sndpcm->buffer == NULL) { loge(E_MALLOC, "size=%zd", sndpcm->period_bytes); goto fail_exit; } return 0; fail_exit: return -1; }
/* write a WAVE-header */ static void begin_wave(int fd, size_t cnt) { WaveHeader h; WaveFmtBody f; WaveChunkHeader cf, cd; int bits; u_int tmp; u_short tmp2; /* WAVE cannot handle greater than 32bit (signed?) int */ if (cnt == (size_t)-2) cnt = 0x7fffff00; bits = 8; switch ((unsigned long) hwparams.format) { case SND_PCM_FORMAT_U8: bits = 8; break; case SND_PCM_FORMAT_S16_LE: bits = 16; break; case SND_PCM_FORMAT_S32_LE: case SND_PCM_FORMAT_FLOAT_LE: bits = 32; break; case SND_PCM_FORMAT_S24_LE: case SND_PCM_FORMAT_S24_3LE: bits = 24; break; default: error(_("Wave doesn't support %s format..."), snd_pcm_format_name(hwparams.format)); exit(EXIT_FAILURE); } h.magic = WAV_RIFF; tmp = cnt + sizeof(WaveHeader) + sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + sizeof(WaveChunkHeader) - 8; h.length = LE_INT(tmp); h.type = WAV_WAVE; cf.type = WAV_FMT; cf.length = LE_INT(16); if (hwparams.format == SND_PCM_FORMAT_FLOAT_LE) f.format = LE_SHORT(WAV_FMT_IEEE_FLOAT); else f.format = LE_SHORT(WAV_FMT_PCM); f.channels = LE_SHORT(hwparams.channels); f.sample_fq = LE_INT(hwparams.rate); #if 0 tmp2 = (samplesize == 8) ? 1 : 2; f.byte_p_spl = LE_SHORT(tmp2); tmp = dsp_speed * hwparams.channels * (u_int) tmp2; #else tmp2 = hwparams.channels * snd_pcm_format_physical_width(hwparams.format) / 8; f.byte_p_spl = LE_SHORT(tmp2); tmp = (u_int) tmp2 * hwparams.rate; #endif f.byte_p_sec = LE_INT(tmp); f.bit_p_spl = LE_SHORT(bits); cd.type = WAV_DATA; cd.length = LE_INT(cnt); if (write(fd, &h, sizeof(WaveHeader)) != sizeof(WaveHeader) || write(fd, &cf, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader) || write(fd, &f, sizeof(WaveFmtBody)) != sizeof(WaveFmtBody) || write(fd, &cd, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) { error(_("write error")); exit(EXIT_FAILURE); } }