Android音频驱动-ASOC之PCM Prepare
来源:互联网 发布:森林法则知乎 编辑:程序博客网 时间:2024/05/20 01:08
ALSA的Prepare流程
snd_pcm_prepare => snd_pcm_action_nonatomic => snd_pcm_action_group => snd_pcm_do_prepare =>
substream->ops->prepare =>soc_pcm_prepare =>rtd->dai_link->ops->prepare => platform->driver->ops->prepare
=>codec_dai->driver->ops->prepare => cpu_dai->driver->ops->prepare
int pcm_write(struct pcm *pcm, const void *data, unsigned int count){ struct snd_xferi x; if (pcm->flags & PCM_IN) return -EINVAL; x.buf = (void*)data; x.frames = count / (pcm->config.channels * pcm_format_to_bits(pcm->config.format) / 8); for (;;) { if (!pcm->running) { int prepare_error = pcm_prepare(pcm);//write之前先prepare if (prepare_error) return prepare_error; if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) return oops(pcm, errno, "cannot write initial data"); pcm->running = 1; return 0; } if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { pcm->prepared = 0; pcm->running = 0; if (errno == EPIPE) { pcm->underruns++; if (pcm->flags & PCM_NORESTART) return -EPIPE; continue; } return oops(pcm, errno, "cannot write stream data"); } return 0; }}// /external/tinyalsa/pcm.c,用户层通过ioctl的方式来调用kernelint pcm_prepare(struct pcm *pcm){ if (pcm->prepared) return 0; if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) return oops(pcm, errno, "cannot prepare channel"); pcm->prepared = 1; return 0;}// /kernel-3.18/sound/core/pcm_native.c,kernel层的实现// 在内核中发起系统调用,执行本应用户空间发起调用的fops函数集,完成参数设置任务/*const struct file_operations snd_pcm_f_ops[2] = { { .owner = THIS_MODULE, .write = snd_pcm_write, .aio_write = snd_pcm_aio_write, .open = snd_pcm_playback_open, .release = snd_pcm_release, .llseek = no_llseek, .poll = snd_pcm_playback_poll, .unlocked_ioctl = snd_pcm_playback_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync, .get_unmapped_area = snd_pcm_get_unmapped_area, }, { .owner = THIS_MODULE, .read = snd_pcm_read, .aio_read = snd_pcm_aio_read, .open = snd_pcm_capture_open, .release = snd_pcm_release, .llseek = no_llseek, .poll = snd_pcm_capture_poll, .unlocked_ioctl = snd_pcm_capture_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync, .get_unmapped_area = snd_pcm_get_unmapped_area, }};*/static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ struct snd_pcm_file *pcm_file; pcm_file = file->private_data; if (((cmd >> 8) & 0xff) != 'A') return -ENOTTY; return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, (void __user *)arg);}static int snd_pcm_playback_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg){ if (snd_BUG_ON(!substream)) return -ENXIO; if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) return -EINVAL; return snd_pcm_common_ioctl1(file, substream, cmd, arg);}static int snd_pcm_common_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg){ ...... case SNDRV_PCM_IOCTL_PREPARE: return snd_pcm_prepare(substream, file); ......}static int snd_pcm_prepare(struct snd_pcm_substream *substream, struct file *file){ int res; struct snd_card *card = substream->pcm->card; int f_flags; if (file) f_flags = file->f_flags; else f_flags = substream->f_flags; snd_power_lock(card); if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, f_flags); snd_power_unlock(card); return res;}static int snd_pcm_action_nonatomic(struct action_ops *ops, struct snd_pcm_substream *substream, int state){ int res; down_read(&snd_pcm_link_rwsem); if (snd_pcm_stream_linked(substream)) res = snd_pcm_action_group(ops, substream, state, 0); else res = snd_pcm_action_single(ops, substream, state); up_read(&snd_pcm_link_rwsem); return res;}static int snd_pcm_action_single(struct action_ops *ops, struct snd_pcm_substream *substream, int state){ int res; res = ops->pre_action(substream, state); if (res < 0) return res; res = ops->do_action(substream, state); if (res == 0) ops->post_action(substream, state); else if (ops->undo_action) ops->undo_action(substream, state); return res;}/*static struct action_ops snd_pcm_action_prepare = { .pre_action = snd_pcm_pre_prepare, .do_action = snd_pcm_do_prepare, .post_action = snd_pcm_post_prepare};*/static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state){ int err; err = substream->ops->prepare(substream); if (err < 0) return err; return snd_pcm_do_reset(substream, 0);}//复位static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state){ struct snd_pcm_runtime *runtime = substream->runtime; int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); runtime->hw_ptr_base = 0; runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size; runtime->silence_start = runtime->status->hw_ptr; runtime->silence_filled = 0; return 0;}
substream的回调函数
//pcm subtream的操作函数/*int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num){ ...... if (rtd->dai_link->dynamic) { rtd->ops.open = dpcm_fe_dai_open; rtd->ops.hw_params = dpcm_fe_dai_hw_params; rtd->ops.prepare = dpcm_fe_dai_prepare; rtd->ops.trigger = dpcm_fe_dai_trigger; rtd->ops.hw_free = dpcm_fe_dai_hw_free; rtd->ops.close = dpcm_fe_dai_close; rtd->ops.pointer = soc_pcm_pointer; rtd->ops.ioctl = soc_pcm_ioctl; } else { rtd->ops.open = soc_pcm_open; rtd->ops.hw_params = soc_pcm_hw_params; rtd->ops.prepare = soc_pcm_prepare; rtd->ops.trigger = soc_pcm_trigger; rtd->ops.hw_free = soc_pcm_hw_free; rtd->ops.close = soc_pcm_close; rtd->ops.pointer = soc_pcm_pointer; rtd->ops.ioctl = soc_pcm_ioctl; } if (platform->driver->ops) { rtd->ops.ack = platform->driver->ops->ack; rtd->ops.copy = platform->driver->ops->copy; rtd->ops.silence = platform->driver->ops->silence; rtd->ops.page = platform->driver->ops->page; rtd->ops.mmap = platform->driver->ops->mmap; } if (playback) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &rtd->ops); if (capture) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &rtd->ops); ......}*/static int soc_pcm_prepare(struct snd_pcm_substream *substream){ 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; struct snd_soc_dai *codec_dai; int i, ret = 0; if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { ret = rtd->dai_link->ops->prepare(substream);//调用dai link driver的prepare } if (platform->driver->ops && platform->driver->ops->prepare) { ret = platform->driver->ops->prepare(substream);//调用platform driver的prepare } for (i = 0; i < rtd->num_codecs; i++) { codec_dai = rtd->codec_dais[i]; if (codec_dai->driver->ops && codec_dai->driver->ops->prepare) { ret = codec_dai->driver->ops->prepare(substream, codec_dai);//调用codec dai driver的prepare } } if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) { ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);//调用cpu dai driver的prepare } /* cancel any delayed stream shutdown that is pending */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && rtd->pop_wait) { rtd->pop_wait = 0; cancel_delayed_work(&rtd->delayed_work); } //把ASoc中的pcm处理部分和dapm进行关联 snd_soc_dapm_stream_event(rtd, substream->stream, SND_SOC_DAPM_STREAM_START); for (i = 0; i < rtd->num_codecs; i++) snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, substream->stream);out: mutex_unlock(&rtd->pcm_mutex); return ret;}
处理platform、codec-dai、cpu-dai的prepare回调函数
//dai link的prepare,没有具体实现/*static struct snd_soc_ops mt_machine_audio_ops = { .startup = mtmachine_startup, .prepare = mtmachine_prepare,};*/static int mtmachine_prepare(struct snd_pcm_substream *substream){ /* pr_debug("mtmachine_prepare\n"); */ return 0;}//platform driver的preparestatic int mtk_pcm_I2S0dl1_prepare(struct snd_pcm_substream *substream){ struct snd_pcm_runtime *runtime = substream->runtime; uint32 MclkDiv3; uint32 u32AudioI2S = 0; bool mI2SWLen; if (mPrepareDone == false) { SetMemifSubStream(Soc_Aud_Digital_Block_MEM_DL1, substream); if (runtime->format == SNDRV_PCM_FORMAT_S32_LE || runtime->format == SNDRV_PCM_FORMAT_U32_LE) { SetMemIfFetchFormatPerSample(Soc_Aud_Digital_Block_MEM_DL1, AFE_WLEN_32_BIT_ALIGN_8BIT_0_24BIT_DATA); SetoutputConnectionFormat(OUTPUT_DATA_FORMAT_24BIT, Soc_Aud_InterConnectionOutput_O03); SetoutputConnectionFormat(OUTPUT_DATA_FORMAT_24BIT, Soc_Aud_InterConnectionOutput_O04); SetoutputConnectionFormat(OUTPUT_DATA_FORMAT_24BIT, Soc_Aud_InterConnectionOutput_O00); SetoutputConnectionFormat(OUTPUT_DATA_FORMAT_24BIT, Soc_Aud_InterConnectionOutput_O01); mI2SWLen = Soc_Aud_I2S_WLEN_WLEN_32BITS; } else { SetMemIfFetchFormatPerSample(Soc_Aud_Digital_Block_MEM_DL1, AFE_WLEN_16_BIT); SetoutputConnectionFormat(OUTPUT_DATA_FORMAT_16BIT, Soc_Aud_InterConnectionOutput_O03); SetoutputConnectionFormat(OUTPUT_DATA_FORMAT_16BIT, Soc_Aud_InterConnectionOutput_O04); SetoutputConnectionFormat(OUTPUT_DATA_FORMAT_16BIT, Soc_Aud_InterConnectionOutput_O00); SetoutputConnectionFormat(OUTPUT_DATA_FORMAT_16BIT, Soc_Aud_InterConnectionOutput_O01); mI2SWLen = Soc_Aud_I2S_WLEN_WLEN_16BITS; } SetSampleRate(Soc_Aud_Digital_Block_MEM_I2S, runtime->rate); /* I2S out Setting */ u32AudioI2S = SampleRateTransform(runtime->rate) << 8; u32AudioI2S |= Soc_Aud_I2S_FORMAT_I2S << 3; /* us3 I2s format */ u32AudioI2S |= Soc_Aud_I2S_WLEN_WLEN_32BITS << 1; /* 32bit */ if (mI2S0dl1_hdoutput_control == true) { /* here to open APLL */ if (!mtk_soc_always_hd) EnableALLbySampleRate(runtime->rate); MclkDiv3 = SetCLkMclk(Soc_Aud_I2S1, runtime->rate); /* select I2S */ MclkDiv3 = SetCLkMclk(Soc_Aud_I2S3, runtime->rate); /* select I2S */ u32AudioI2S |= Soc_Aud_LOW_JITTER_CLOCK << 12; /* Low jitter mode */ } else u32AudioI2S &= ~(Soc_Aud_LOW_JITTER_CLOCK << 12); #ifdef CONFIG_MTK_SMARTPA_SUPPORT /* use low jitter mode for smart pa */ u32AudioI2S |= Soc_Aud_LOW_JITTER_CLOCK << 12; /* Low jitter mode */ #endif if (GetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_2) == false) { SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_2, true); Afe_Set_Reg(AFE_I2S_CON3, u32AudioI2S | 1, AFE_MASK_ALL); } else SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_2, true); /* start I2S DAC out */ if (GetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC) == false) { SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC, true); SetI2SDacOut(substream->runtime->rate, mI2S0dl1_hdoutput_control, mI2SWLen); SetI2SDacEnable(true); } else SetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC, true); if (mI2S0dl1_hdoutput_control == true) { EnableI2SDivPower(AUDIO_APLL12_DIV2, true); EnableI2SDivPower(AUDIO_APLL12_DIV4, true); } EnableAfe(true); if (GetMemoryPathEnable(Soc_Aud_Digital_Block_I2S_OUT_DAC) == true) SetI2SADDAEnable(true); mPrepareDone = true; } return 0;}//codec dai driver的prepare/*static const struct snd_soc_dai_ops mt6323_aif1_dai_ops = { .startup = mt63xx_codec_startup, .prepare = mt63xx_codec_prepare, .trigger = mt6323_codec_trigger,};*/static int mt63xx_codec_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *Daiport){ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { mBlockSampleRate[AUDIO_ANALOG_DEVICE_IN_ADC] = substream->runtime->rate; } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { mBlockSampleRate[AUDIO_ANALOG_DEVICE_OUT_DAC] = substream->runtime->rate; } return 0;}//cpu dai driver的prepare,没有实现prepare/*static struct snd_soc_dai_ops mtk_dai_stub_ops = { .startup = multimedia_startup,};*/
发生stream事件时,会触发snd_soc_dapm_stream_even。什么叫stream事件?
准备或关闭一个pcm stream通道(snd_pcm_prepare/snd_pcm_close)这些都属于stream事件。
另外suspend或resume时,也会触发snd_soc_dapm_stream_event处理。
void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event){ struct snd_soc_card *card = rtd->card; mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); soc_dapm_stream_event(rtd, stream, event); mutex_unlock(&card->dapm_mutex);}static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, int event){ int i; soc_dapm_dai_stream_event(rtd->cpu_dai, stream, event); //遍历codec每个dapm widget,如果该widget的stream name与传递进来的stream参数相匹配,如果匹配则置widget->active为真 。 for (i = 0; i < rtd->num_codecs; i++) soc_dapm_dai_stream_event(rtd->codec_dais[i], stream, event); dapm_power_widgets(rtd->card, event);//触发dapm,重置相关的widgets}
阅读全文
0 0
- Android音频驱动-ASOC之PCM Prepare
- Android音频驱动-ASOC之PCM Open
- Android音频驱动-ASOC之PCM Write
- Android音频驱动-ASOC之PCM Device创建
- Android音频驱动-ASOC之PCM HW Params
- 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驱动架构
- Python之,requests包
- php使用openssl来实现非对称加密 及原理理解
- 生成某个范围内N个不重复随机数与生成固定长度数组
- 在安装nodejs时遇到的错误提示:
- 代码笔记--朴素贝叶斯
- Android音频驱动-ASOC之PCM Prepare
- iOS逆向研究01
- 欢迎使用CSDN-markdown编辑器
- 解决importerror no module named mysqldb
- XSS跨站脚步攻击及防范
- Substring Anagrams
- mac电脑原始创建vue框架及运行项目
- 如何设置mysql数据库为utf-8编码
- UVa 12136