如何分析tinyplay 播放音频和tinymix的过程?需要相应的工具来支持追查;

一、分析tinyplay和tinymix:

1.1 利用strace工具:

strace -o tinyplay.log tinyplay 1.wav

strace -o tinymixer.log tinymixer "SEC_MI2S_RX Audio Mixer MultiMedia1" 1

利用strace工具获取APP的log,从应用层往下看;

1.2 分析alsa-utils源码:

tiny工具源码在android/external/tinyalsa目录下;

二、tinyplay调用分析(tinyplay.log搜索设备节点“/dev/snd/pcmC0D0p”)

2.1 tinyplay的open过程:

snd_pcm_f_ops[0]是播放音频的file_operations,snd_pcm_f_ops[1]则是录音的file_operations:

  1. const struct file_operations snd_pcm_f_ops[] = {
  2. {
  3. .owner = THIS_MODULE,
  4. .write = snd_pcm_write,
  5. .aio_write = snd_pcm_aio_write,
  6. .open = snd_pcm_playback_open,
  7. .release = snd_pcm_release,
  8. .llseek = no_llseek,
  9. .poll = snd_pcm_playback_poll,
  10. .unlocked_ioctl = snd_pcm_playback_ioctl,
  11. .compat_ioctl = snd_pcm_ioctl_compat,
  12. .mmap = snd_pcm_mmap,
  13. .fasync = snd_pcm_fasync,
  14. .get_unmapped_area = snd_pcm_get_unmapped_area,
  15. },
  16. {
  17. .owner = THIS_MODULE,
  18. .read = snd_pcm_read,
  19. .aio_read = snd_pcm_aio_read,
  20. .open = snd_pcm_capture_open,
  21. .release = snd_pcm_release,
  22. .llseek = no_llseek,
  23. .poll = snd_pcm_capture_poll,
  24. .unlocked_ioctl = snd_pcm_capture_ioctl,
  25. .compat_ioctl = snd_pcm_ioctl_compat,
  26. .mmap = snd_pcm_mmap,
  27. .fasync = snd_pcm_fasync,
  28. .get_unmapped_area = snd_pcm_get_unmapped_area,
  29. }
  30. };

我们从snd_pcm_playback_open函数开始向下分析:

  1. static int snd_pcm_playback_open(struct inode *inode, struct file *file)
  2. {
  3. struct snd_pcm *pcm;
  4. int err = nonseekable_open(inode, file);
  5. if (err < )
  6. return err;
  7. pcm = snd_lookup_minor_data(iminor(inode),
  8. SNDRV_DEVICE_TYPE_PCM_PLAYBACK);  //取得其私有数据并返回的
  9. err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
  10. if (pcm)
  11. snd_card_unref(pcm->card);      //减少设备对象的引用计数 snd_card_unref(card);
  12. return err;
  13. }

在下面调用了snd_pcm_open函数:

  1. static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
  2. {
  3. int err;
  4. wait_queue_t wait;
  5.  
  6. if (pcm == NULL) {
  7. err = -ENODEV;
  8. goto __error1;
  9. }
  10. err = snd_card_file_add(pcm->card, file);
  11. if (err < )
  12. goto __error1;
  13. if (!try_module_get(pcm->card->module)) {
  14. err = -EFAULT;
  15. goto __error2;
  16. }
  17. init_waitqueue_entry(&wait, current);
  18. add_wait_queue(&pcm->open_wait, &wait);
  19. mutex_lock(&pcm->open_mutex);
  20. while () {
  21. err = snd_pcm_open_file(file, pcm, stream);  // 将操作该声卡card的应用程序添加到card->files_list
  22. if (err >= )
  23. break;
  24. if (err == -EAGAIN) {
  25. if (file->f_flags & O_NONBLOCK) {
  26. err = -EBUSY;
  27. break;
  28. }
  29. } else
  30. break;
  31. set_current_state(TASK_INTERRUPTIBLE);
  32. mutex_unlock(&pcm->open_mutex);
  33. schedule();
  34. mutex_lock(&pcm->open_mutex);
  35. if (pcm->card->shutdown) {
  36. err = -ENODEV;
  37. break;
  38. }
  39. if (signal_pending(current)) {
  40. err = -ERESTARTSYS;
  41. break;
  42. }
  43. }
  44. remove_wait_queue(&pcm->open_wait, &wait);
  45. mutex_unlock(&pcm->open_mutex);
  46. if (err < )
  47. goto __error;
  48. return err;
  49.  
  50. __error:
  51. module_put(pcm->card->module);
  52. __error2:
  53. snd_card_file_remove(pcm->card, file);
  54. __error1:
  55. return err;
  56. }

再从snd_pcm_open_file继续向下看:

  1. static int snd_pcm_open_file(struct file *file,
  2. struct snd_pcm *pcm,
  3. int stream)
  4. {
  5. struct snd_pcm_file *pcm_file;
  6. struct snd_pcm_substream *substream;
  7. int err;
  8.  
  9. err = snd_pcm_open_substream(pcm, stream, file, &substream);    //打开substream结构体
  10. if (err < )
  11. return err;
  12.  
  13. pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
  14. if (pcm_file == NULL) {
  15. snd_pcm_release_substream(substream);
  16. return -ENOMEM;
  17. }
  18. pcm_file->substream = substream;
  19. if (substream->ref_count == ) {
  20. substream->file = pcm_file;
  21. substream->pcm_release = pcm_release_private;
  22. }
  23. file->private_data = pcm_file;
  24.  
  25. return ;
  26. }
  1. int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
  2. struct file *file,
  3. struct snd_pcm_substream **rsubstream)
  4. {
  5. struct snd_pcm_substream *substream;
  6. int err;
  7.  
  8. err = snd_pcm_attach_substream(pcm, stream, file, &substream);
  9. if (err < )
  10. return err;
  11. if (substream->ref_count > ) {
  12. *rsubstream = substream;
  13. return ;
  14. }
  15.  
  16. err = snd_pcm_hw_constraints_init(substream); //初始化substream结构体
  17. if (err < ) {
  18. snd_printd("snd_pcm_hw_constraints_init failed\n");
  19. goto error;
  20. }
  21.  
  22. if ((err = substream->ops->open(substream)) < )
  23. goto error;
  24.  
  25. substream->hw_opened = ;
  26.  
  27. err = snd_pcm_hw_constraints_complete(substream);
  28. if (err < ) {
  29. snd_printd("snd_pcm_hw_constraints_complete failed\n");
  30. goto error;
  31. }
  32.  
  33. *rsubstream = substream;
  34. return ;
  35.  
  36. error:
  37. snd_pcm_release_substream(substream);
  38. return err;
  39. }

snd_pcm_open_substream

在snd_pcm_open_substream函数中:

  1. if ((err = substream->ops->open(substream)) < )    // substream->ops : snd_pcm_ops结构体
  2. goto error;

依次调用cpu_dai, dma, codec_dai, machine(三大模块)的open或startup函数;

msm_mi2s_snd_startup函数:

  1. struct snd_soc_pcm_runtime *rtd = substream->private_data;
  2. struct snd_soc_card *card = rtd->card;
  3. struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
  4. struct snd_soc_codec *codec = rtd->codec;

设置snd_soc_pcm_runtime的cpu、codec等模块;然后在snd_soc_pcm_runtime函数中对codec函数进行相应的设置,之后通过音频数据流通道播放出声音;

调用过程如下图:

2.2 tinyplay的ioctl过程:

同样也是snd_pcm_f_ops[0]结构体的file_operations:

  1. {
  2. .owner = THIS_MODULE,
  3. .write = snd_pcm_write,
  4. .aio_write = snd_pcm_aio_write,
  5. .open = snd_pcm_playback_open,
  6. .release = snd_pcm_release,
  7. .llseek = no_llseek,
  8. .poll = snd_pcm_playback_poll,
  9. .unlocked_ioctl = snd_pcm_playback_ioctl,
  10. .compat_ioctl = snd_pcm_ioctl_compat,
  11. .mmap = snd_pcm_mmap,
  12. .fasync = snd_pcm_fasync,
  13. .get_unmapped_area = snd_pcm_get_unmapped_area,
  14. },

从snd_pcm_playback_ioctl函数向下看:

  1. static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
  2. unsigned long arg)
  3. {
  4. struct snd_pcm_file *pcm_file;
  5.  
  6. pcm_file = file->private_data;    //获取相应的私有数据
  7.  
  8. if ((((cmd >> ) & 0xff) != 'A') && (((cmd >> ) & 0xff) != 'C'))
  9. return -ENOTTY;
  10.  
  11. return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
  12. (void __user *)arg);
  13. }

snd_pcm_playback_ioctl1:

  1. static int snd_pcm_playback_ioctl1(struct file *file,
  2. struct snd_pcm_substream *substream,
  3. unsigned int cmd, void __user *arg)
  4. {
  5. if (snd_BUG_ON(!substream))
  6. return -ENXIO;
  7. if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
  8. return -EINVAL;
  9. //根据case不同,对播放进行相应的不同操作
  10. switch (cmd) {
  11. case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
  12. {
  13. struct snd_xferi xferi;
  14. struct snd_xferi __user *_xferi = arg;
  15. struct snd_pcm_runtime *runtime = substream->runtime;
  16. snd_pcm_sframes_t result;
  17. if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
  18. return -EBADFD;
  19. if (put_user(, &_xferi->result))
  20. return -EFAULT;
  21. if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
  22. return -EFAULT;
  23. result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
  24. __put_user(result, &_xferi->result);
  25. return result < ? result : ;
  26. }
  27. case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
  28. {
  29. struct snd_xfern xfern;
  30. struct snd_xfern __user *_xfern = arg;
  31. struct snd_pcm_runtime *runtime = substream->runtime;
  32. void __user **bufs;
  33. snd_pcm_sframes_t result;
  34. if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
  35. return -EBADFD;
  36. if (runtime->channels > )
  37. return -EINVAL;
  38. if (put_user(, &_xfern->result))
  39. return -EFAULT;
  40. if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
  41. return -EFAULT;
  42.  
  43. bufs = memdup_user(xfern.bufs,
  44. sizeof(void *) * runtime->channels);
  45. if (IS_ERR(bufs))
  46. return PTR_ERR(bufs);
  47. result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
  48. kfree(bufs);
  49. __put_user(result, &_xfern->result);
  50. return result < ? result : ;
  51. }
  52. case SNDRV_PCM_IOCTL_REWIND:
  53. {
  54. snd_pcm_uframes_t frames;
  55. snd_pcm_uframes_t __user *_frames = arg;
  56. snd_pcm_sframes_t result;
  57. if (get_user(frames, _frames))
  58. return -EFAULT;
  59. if (put_user(, _frames))
  60. return -EFAULT;
  61. result = snd_pcm_playback_rewind(substream, frames);
  62. __put_user(result, _frames);
  63. return result < ? result : ;
  64. }
  65. case SNDRV_PCM_IOCTL_FORWARD:
  66. {
  67. snd_pcm_uframes_t frames;
  68. snd_pcm_uframes_t __user *_frames = arg;
  69. snd_pcm_sframes_t result;
  70. if (get_user(frames, _frames))
  71. return -EFAULT;
  72. if (put_user(, _frames))
  73. return -EFAULT;
  74. result = snd_pcm_playback_forward(substream, frames);
  75. __put_user(result, _frames);
  76. return result < ? result : ;
  77. }
  78. }
  79. return snd_pcm_common_ioctl1(file, substream, cmd, arg);
  80. }

从snd_pcm_common_ioctl1继续分析,进入函数的prepare中:

当函数prepare完毕后,就一切准备就绪了,只等一个trigger;而trigger的执行会在上层的alsalib调用write的函数触发;prepare过程可以看下图,具体就不继续分析了:

下一节我们将来分析tinymixer的调用过程;

alsa声卡分析alsa-utils调用过程(二)-tinymixer

alsa声卡分析alsa-utils调用过程的更多相关文章

  1. alsa声卡分析alsa-utils调用过程(一)-tinyplay

    如何分析tinyplay 播放音频和tinymix的过程?需要相应的工具来支持追查: 一.分析tinyplay和tinymix: 1.1 利用strace工具: strace -o tinyplay. ...

  2. Spring源码分析之`BeanFactoryPostProcessor`调用过程

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 本文内容: AbstractApplicationContext#refresh前部分的一点小内容 ...

  3. alsa声卡分析alsa-utils调用过程(二)-tinymixer

    继上一篇文章:http://www.cnblogs.com/linhaostudy/p/8515277.html 三.tinymixer调用分析:(tinymixer.log搜索节点:/dev/snd ...

  4. mybatis源码分析(方法调用过程)

    十一月月底,宿舍楼失火啦,搞得20多天没有网,目测直到放假也不会来了... 正题 嗯~,其实阅读源码不是为了应付面试,更重要的让你知道,大师是怎样去写代码的,同样是用Java,为啥Clinton Be ...

  5. Openstack Nova 源码分析 — RPC 远程调用过程

    目录 目录 Nova Project Services Project 的程序入口 setuppy Nova中RPC远程过程调用 nova-compute RPC API的实现 novacompute ...

  6. ALSA声卡07_分析调用过程_学习笔记

    1.编译新的strace工具分析aplay和amixer应用程序对声卡的调用过程 (1)因为旧的strace工具不能识别不能识别alsa声卡驱动程序里面的ioctrl. (2)编译过程参考http:/ ...

  7. ALSA声卡笔记1---ALSA驱动框架

    1.声卡驱动程序sound.c (1)入口函数里通过register_chrdev()函数注册file_operations 结构体 (2)file_operations 结构体,里面只有open函数 ...

  8. ALSA声卡驱动中的DAPM详解之七:dapm事件机制(dapm event)

    前面的六篇文章,我们已经讨论了dapm关于动态电源管理的有关知识,包括widget的创建和初始化,widget之间的连接以及widget的上下电顺序等等.本章我们准备讨论dapm框架中的另一个机制:事 ...

  9. ALSA声卡驱动中的DAPM详解之五:建立widget之间的连接关系

    前面我们主要着重于codec.platform.machine驱动程序中如何使用和建立dapm所需要的widget,route,这些是音频驱动开发人员必须要了解的内容,经过前几章的介绍,我们应该知道如 ...

随机推荐

  1. 【php】phpExcel使用教程,如何导出excel表格

    [1]下载phpExcel类文件 可在官方去下载 我们只需要classes中的文件,把Classes文件复制到项目中 只需要2个文件就可以了  一个就是phpExcel(刚才我们复制过来的文件 Cla ...

  2. linux配置上网

    重装系统之后,配置虚拟机的网络问题花了我三个小时,忘记了网关是vmnet8的IP还是DNS了,搞了很久,后来碰运气碰对了. 寄宿机共享的网络是vmnet8,设置IP,DNS,是vmnet8 的IPv4 ...

  3. docker命令行学习

    docker命令行学习 docker run docker run --help:老实说这条最管用了 docker run -it:交互模式,允许控制台输出 docker run -d:detach, ...

  4. BZOJ 3729: Gty的游戏 [伪ETT 博弈论]【学习笔记】

    题意: 给定一棵有根树,每个节点有一些石子,每次可以将不多于k的石子移动到父节点 修改一个点的石子数,插入一个点,询问某棵子树是否先手必胜 显然是一个阶梯Nim 每次最多取k个,找规律或者观察式子易发 ...

  5. BZOJ 1856: [Scoi2010]字符串 [Catalan数]

    1856: [Scoi2010]字符串 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1418  Solved: 790[Submit][Status][ ...

  6. BZOJ 2111: [ZJOI2010]Perm 排列计数 [Lucas定理]

    2111: [ZJOI2010]Perm 排列计数 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1936  Solved: 477[Submit][ ...

  7. HDU1013,1163 ,2035九余数定理 快速幂取模

    1.HDU1013求一个positive integer的digital root,即不停的求数位和,直到数位和为一位数即为数根. 一开始,以为integer嘛,指整型就行吧= =(too young ...

  8. 记一次酷狗音乐API的获取,感兴趣的可以自己封装开发自己的音乐播放器

    1.本教程仅供个人学习用,禁止用于任何的商业和非法用途,如涉及版权问题请联系笔者删除. 2.随笔系作者原创文档,转载请注明文档来源:http://www.cnblogs.com/apresunday/ ...

  9. Selenium_WebDriver_控制浏览器

    版权声明:本文为博主原创文章,转载请注明出处.  浏览器环境: ①GoogleChrome:60 ②chromedriver:2.30: 访问 操作 方法 示例 访问页面 void get(java. ...

  10. [Python Study Notes] Python的安装

    Windows: 1.下载安装包: 转到Python官网https://www.python.org/downloads/  ,下载最新版本的Python. 2.安装 安装到自定义的安装路径下. 3. ...