1.USB-AUDIO的声卡注册过程
usb_probe_interface    ----  driver.cusb_audio_probe    ----  card.csnd_usb_create_stream    ----  card.csnd_usb_parse_audio_interface    ----  stream.csnd_usb_add_audio_stream    ----  stream.csnd_pcm_new    ----  pcm.c_snd_pcm_new    ----  pcm.cstatic struct snd_device_ops ops = {.dev_free = snd_pcm_dev_free,.dev_register =  snd_pcm_dev_register,.dev_disconnect = snd_pcm_dev_disconnect,};snd_pcm_new_stream(...,SNDRV_PCM_STREAM_PLAYBACK,...)    ----  pcm.csnd_pcm_new_stream(...,SNDRV_PCM_STREAM_CAPTURE,...)    ----  pcm.csnd_device_new    ----  pcm.c
struct snd_pcm {//是分别对应的2条音频流,一条是playback,一条是capturestruct snd_pcm_str streams[2];
};
_snd_pcm_new中有个函数需要特别关注如下:
snd_pcm_dev_register...for (cidx = 0; cidx < 2; cidx++) {...switch (cidx) {case SNDRV_PCM_STREAM_PLAYBACK:sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;break;case SNDRV_PCM_STREAM_CAPTURE:sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;break;}...snd_register_device_for_dev(devtype, pcm->card,pcm->device,&snd_pcm_f_ops[cidx],pcm, str, dev)...
如上是注册pcm设备的地方,同时我们需要关注pcm设备的ops,如下:
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,}
};

之后pcm的录音和播放都会通过这个ops完成
2.使用tinycap的录音过程

external\tinyalsa\tinycap.c
int main(){//先预先留出wav的头部fseek(file, sizeof(struct wav_header), SEEK_SET);frames = capture_sample(file, card, device, header.num_channels,header.sample_rate, format,period_size, period_count);//写入头部fseek(file, 0, SEEK_SET);fwrite(&header, sizeof(struct wav_header), 1, file);
}

一帧音频数据大小 = 通道数 * 采样深度

Period size:周期,每次硬件中断处理音频数据的帧数,对于音频设备的数据读写,以此为单位。

继续来看capture_sample

capture_sample打开声卡的音频设备"/dev/snd/pcmC1D0c","/dev/snd/pcmC1D0p",其中"c"对应capture,"p"对应的是playpcm_open(card, device, PCM_IN, &config);通过样本大小(4个硬件周期,每个周期处理1024帧数据)获取总字节数size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));为这次样本的采集准备空间buffer = malloc(size);通过pcm_read从内核中获取音频数据到buffer中,随后将这个buffer的内容写入到文件file中,持续的读取声卡中的音频,直到结束录音while (capturing && !pcm_read(pcm, buffer, size)) {if (fwrite(buffer, 1, size, file) != size) {fprintf(stderr,"Error capturing sample\n");break;}bytes_read += size;}录音结束,释放buffer,关闭pcm设备,返回当前读取到的音频帧数free(buffer);pcm_close(pcm);return pcm_bytes_to_frames(pcm, bytes_read);

随后进入到alsa的音频库(libtinyalsa.so)中

external\tinyalsa\pcm.c
int pcm_read(struct pcm *pcm, void *data, unsigned int count)
{struct snd_xferi x;int len = 10;if (!(pcm->flags & PCM_IN))return -EINVAL;//x.buf指向的是内核返回的音频Buf数据x.buf = data;//x.frames 对应的是要收集满count个字节的音频数据,对应的声卡pcm设备需要采集的帧数x.frames = count / (pcm->config.channels *pcm_format_to_bits(pcm->config.format) / 8);for (;;) {if (!pcm->running) {if (pcm_start(pcm) < 0) {fprintf(stderr, "start error");return -errno;}}通过ioctl调度到到内核完成if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {pcm->prepared = 0;pcm->running = 0;if (errno == EPIPE) {/* we failed to make our window -- try to restart */pcm->underruns++;continue;}return oops(pcm, errno, "cannot read stream data");}return 0;}
}

3.tinycap的录音过程进入内核

snd_pcm_capture_ioctlsnd_pcm_capture_ioctl1snd_pcm_lib_readsnd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer)
ok,我们看看snd_pcm_lib_read1这个函数snd_pcm_lib_read1....//这里实现的是一个等待队列,等待usb收集到足够的音频数据后会返回avail的值wait_for_avail(substream, &avail);//调用transfer的函数指针callback到userspacetransfer(substream, appl_ofs, data, offset, frames);

USB采集音频数据的大致流程如下:

最后回到transfer的函数指针实现

static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream, unsigned int hwoff,unsigned long data, unsigned int off,snd_pcm_uframes_t frames)
{struct snd_pcm_runtime *runtime = substream->runtime;int err;char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);if (substream->ops->copy) {if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)return err;} else {//走这儿,很简单,就是将dma采集到的buf传递到用户空间,完事char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))return -EFAULT;}return 0;
}

Android USB AUDIO初步分析相关推荐

  1. usb4java android,USB audio on Android platform

    这种是android 手机为Host, audio设备为device. 以MSM8x26  android 5.0/5.1 (Lolliop) 为例 1. source code • Kernel k ...

  2. Android USB audio on Android platform

    这种是android手机为Host, audio设备为device. 以MSM8x26 android 5.0/5.1 (Lolliop) 为例1. source code •Kernelkernel ...

  3. Android USB Audio accessory设备

    这个手机做device, audio accessory是Host. 以高通msm8x26(USB2.0) Lolliop android 5.0/5.1为例1 代码•Kernelkernel/dri ...

  4. Android usb audio信息获取(一)

    android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...

  5. Android usb audio调用流程(二)

    android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...

  6. Android usb audio录音(四)

    android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...

  7. Android Audio代码分析(2): AudioPoilicyService 启动

    policy: 设备的选择 https://www.cxyzjd.com/article/VNanyesheshou/115659838 Android 音频源码分析--AudioTrack设备选择_ ...

  8. Android USB Accessory分析

    转自:https://blog.csdn.net/yingzhao80/article/details/45511351 Android下USB Accessory的实现分析 摘要:本文介绍了USB ...

  9. android挂载usb设备,android usb挂载分析---MountService启动

    在android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动, ...

最新文章

  1. 自动分析源代码,创建函数地图展示调用关系
  2. Transient关键字的使用
  3. Unity3D之预设
  4. symantec 操作 重叠vo_无关收购 谈谈赛门铁克的产品策略思路
  5. 遍历文件夹还原数据库SQL语句
  6. Hadoop入门(八)Mapreduce高级shuffle之Partitioner
  7. Oracle教程之oracle 给用户授权
  8. 基于php校园失物招领,校园失物招领系统设计
  9. Codeforces-Div312
  10. JSP实用教程 第三章 JSP内置对象
  11. ROS端口映射这样才正确
  12. 获取网站url ico小图标
  13. 平板游戏交互式设计的10大规则
  14. 戴尔微型计算机7050配置,小巧彪悍 戴尔 OptiPlex 7050 微型机评测
  15. android虚拟按键
  16. 美国参议员建议立法“黑掉国土安全部”
  17. 系统分析师-资料总结-中
  18. VB.net是个弥天大谎,VB.net已死(海康威视 SDK 开发有感)
  19. od使用的小tips
  20. Arcmap做地图要领总结

热门文章

  1. python第三库安装方法记录
  2. 【AtCoder】ARC 081 E - Don't Be a Subsequence
  3. UITextField监控文字变化方法
  4. python start
  5. java web 开发分层
  6. 从天天爱消除和节奏大师的用户对于论坛形式的分析
  7. 黑马程序员-面向对象-08天-2 (多态)
  8. Storm-Engine 基于 C++ 的开源游戏引擎
  9. Excel Spreadsheet 转换web HTML 5 展示
  10. 【机器人】机械臂与动捕Nokov的深入了解