Android音频驱动-ASOC之PCM HW Params
来源:互联网 发布:java modbus与rs485 编辑:程序博客网 时间:2024/05/20 05:27
ALSA的HW_param流程
soc_pcm_hw_params => rtd->dai_link->ops->hw_params => codec_dai->driver->ops->hw_params =>
cpu_dai->driver->ops->hw_params => platform->driver->ops->hw_params
struct pcm *pcm_open(unsigned int card, unsigned int device, unsigned int flags, struct pcm_config *config){ struct pcm *pcm; struct snd_pcm_info info; struct snd_pcm_hw_params params; struct snd_pcm_sw_params sparams; char fn[256]; int rc; pcm = calloc(1, sizeof(struct pcm)); if (!pcm || !config) return &bad_pcm; /* TODO: could support default config here */ pcm->config = *config; snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, flags & PCM_IN ? 'c' : 'p'); pcm->flags = flags; pcm->fd = open(fn, O_RDWR); if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { oops(pcm, errno, "cannot get info"); goto fail_close; } param_init(¶ms); param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, pcm_format_to_alsa(config->format)); param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, SNDRV_PCM_SUBFORMAT_STD); param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, pcm_format_to_bits(config->format)); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, pcm_format_to_bits(config->format) * config->channels); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, config->channels); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count); param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, config->rate); param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_RW_INTERLEAVED); if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { oops(pcm, errno, "cannot set hw params"); goto fail_close; } /* get our refined hw_params */ config->period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); config->period_count = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS); pcm->buffer_size = config->period_count * config->period_size; memset(&sparams, 0, sizeof(sparams)); sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; sparams.period_step = 1; if (!config->start_threshold) { if (pcm->flags & PCM_IN) pcm->config.start_threshold = sparams.start_threshold = 1; else pcm->config.start_threshold = sparams.start_threshold = config->period_count * config->period_size / 2; } else sparams.start_threshold = config->start_threshold; /* pick a high stop threshold - todo: does this need further tuning */ if (!config->stop_threshold) { if (pcm->flags & PCM_IN) pcm->config.stop_threshold = sparams.stop_threshold = config->period_count * config->period_size * 10; else pcm->config.stop_threshold = sparams.stop_threshold = config->period_count * config->period_size; } else sparams.stop_threshold = config->stop_threshold; if (!pcm->config.avail_min) { if (pcm->flags & PCM_MMAP) pcm->config.avail_min = sparams.avail_min = pcm->config.period_size; else pcm->config.avail_min = sparams.avail_min = 1; } else sparams.avail_min = config->avail_min; sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ sparams.silence_threshold = config->silence_threshold; sparams.silence_size = config->silence_size; pcm->boundary = sparams.boundary = pcm->buffer_size; while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) pcm->boundary *= 2; if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { oops(pcm, errno, "cannot set sw params"); goto fail; } rc = pcm_hw_mmap_status(pcm); pcm->underruns = 0; return pcm;}static int snd_pcm_common_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg){ switch (cmd) { case SNDRV_PCM_IOCTL_HW_PARAMS: return snd_pcm_hw_params_user(substream, arg);}
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream, struct snd_pcm_hw_params __user * _params){ struct snd_pcm_hw_params *params; int err; params = memdup_user(_params, sizeof(*params)); err = snd_pcm_hw_params(substream, params); if (copy_to_user(_params, params, sizeof(*params))) { if (!err) err = -EFAULT; } kfree(params); return err;}static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params){ struct snd_pcm_runtime *runtime; int err, usecs; unsigned int bits; snd_pcm_uframes_t frames; runtime = substream->runtime; snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: break; default: snd_pcm_stream_unlock_irq(substream); return -EBADFD; } snd_pcm_stream_unlock_irq(substream); if (atomic_read(&substream->mmap_count)) return -EBADFD; params->rmask = ~0U; err = snd_pcm_hw_refine(substream, params); err = snd_pcm_hw_params_choose(substream, params); if (substream->ops->hw_params != NULL) { err = substream->ops->hw_params(substream, params); } runtime->access = params_access(params); runtime->format = params_format(params); runtime->subformat = params_subformat(params); runtime->channels = params_channels(params); runtime->rate = params_rate(params); runtime->period_size = params_period_size(params); runtime->periods = params_periods(params); runtime->buffer_size = params_buffer_size(params); runtime->info = params->info; runtime->rate_num = params->rate_num; runtime->rate_den = params->rate_den; runtime->no_period_wakeup = (params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) && (params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP); bits = snd_pcm_format_physical_width(runtime->format); runtime->sample_bits = bits; bits *= runtime->channels; runtime->frame_bits = bits; frames = 1; while (bits % 8 != 0) { bits *= 2; frames *= 2; } runtime->byte_align = bits / 8; runtime->min_align = frames; /* Default sw params */ runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; runtime->period_step = 1; runtime->control->avail_min = runtime->period_size; runtime->start_threshold = 1; runtime->stop_threshold = runtime->buffer_size; runtime->silence_threshold = 0; runtime->silence_size = 0; runtime->boundary = runtime->buffer_size; while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) runtime->boundary *= 2; snd_pcm_timer_resolution_change(substream); snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP); if (pm_qos_request_active(&substream->latency_pm_qos_req)) pm_qos_remove_request(&substream->latency_pm_qos_req); if ((usecs = period_to_usecs(runtime)) >= 0) pm_qos_add_request(&substream->latency_pm_qos_req, PM_QOS_CPU_DMA_LATENCY, usecs); return 0;}static int soc_pcm_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_platform *platform = rtd->platform; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int i, ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); ret = soc_pcm_params_symmetry(substream, params); if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { //dai link driver没有实现hw_params ret = rtd->dai_link->ops->hw_params(substream, params); } for (i = 0; i < rtd->num_codecs; i++) { struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; struct snd_pcm_hw_params codec_params; /* copy params for each codec */ codec_params = *params; /* fixup params based on TDM slot masks */ if (codec_dai->tx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->tx_mask); if (codec_dai->rx_mask) soc_pcm_codec_params_fixup(&codec_params, codec_dai->rx_mask); //codec dai driver没有实现hw_params ret = soc_dai_hw_params(substream, &codec_params, codec_dai); codec_dai->rate = params_rate(&codec_params); codec_dai->channels = params_channels(&codec_params); codec_dai->sample_bits = snd_pcm_format_physical_width( params_format(&codec_params)); } //cpu dai driver没有实现hw_params ret = soc_dai_hw_params(substream, params, cpu_dai); if (platform->driver->ops && platform->driver->ops->hw_params) { //调用platform driver的hw_params函数 ret = platform->driver->ops->hw_params(substream, params); } /* store the parameters for each DAIs */ cpu_dai->rate = params_rate(params); cpu_dai->channels = params_channels(params); cpu_dai->sample_bits = snd_pcm_format_physical_width(params_format(params));out: mutex_unlock(&rtd->pcm_mutex); return ret;}//调用cpu dai driver和codec dai driver的具体实现int soc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai){ int ret; if (dai->driver->ops && dai->driver->ops->hw_params) { ret = dai->driver->ops->hw_params(substream, params, dai); } return 0;}
platform driver实例的实现
static int mtk_pcm_I2S0dl1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params){ int ret = 0; substream->runtime->dma_bytes = params_buffer_bytes(hw_params); if (mPlaybackSramState == SRAM_STATE_PLAYBACKFULL) { substream->runtime->dma_area = (unsigned char *)Get_Afe_SramBase_Pointer(); substream->runtime->dma_addr = AFE_INTERNAL_SRAM_PHY_BASE; SetHighAddr(Soc_Aud_Digital_Block_MEM_DL1, false); AudDrv_Allocate_DL1_Buffer(mDev, substream->runtime->dma_bytes); } else { substream->runtime->dma_bytes = params_buffer_bytes(hw_params); substream->runtime->dma_area = Dl1_Playback_dma_buf->area; substream->runtime->dma_addr = Dl1_Playback_dma_buf->addr; SetHighAddr(Soc_Aud_Digital_Block_MEM_DL1, true); SetDL1Buffer(substream, hw_params); } return ret;}
阅读全文
0 0
- Android音频驱动-ASOC之PCM HW Params
- Android音频驱动-ASOC之PCM Open
- Android音频驱动-ASOC之PCM Prepare
- Android音频驱动-ASOC之PCM Write
- Android音频驱动-ASOC之PCM Device创建
- Android音频驱动-ASOC之Machine
- Android音频驱动-ASOC之Codec
- Android音频驱动-ASOC之Platform
- Android音频驱动-ASOC之CPU DAI
- Android音频驱动-ASOC之常用对象
- Android音频驱动-ASOC之Control Open
- Android音频驱动-ASOC之DAMP
- Android音频驱动-ASOC之Sound Card注册
- Android音频驱动-ASOC之Sound Card创建
- Android音频驱动-ASOC之主&从设备号
- Android音频驱动-ASOC之创建设备节点
- Android音频驱动-ASOC之Control Device创建
- Linux音频驱动之ASoC驱动架构
- Bootstrap框架----地址联动--选择地址
- 【IIS】启用IIS
- Ti437x LED总线驱动模型程序+设备树
- SonarQube Scanner 安装使用文档
- linux下svn服务器搭建及虚拟机网路问题
- Android音频驱动-ASOC之PCM HW Params
- python第三方插件face_recognition
- 【TL8266】显示BLE设备列表
- oracle11g 建立全文索引
- Hibernate的事务
- Android 6.0 权限处理( Permission Denial异常)
- 【PAT 1003 Highest Price in Supply Chain (25)】 & dfs
- 软件测试报告问题等级划分
- 表的操作