Android USB AUDIO初步分析
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初步分析相关推荐
- usb4java android,USB audio on Android platform
这种是android 手机为Host, audio设备为device. 以MSM8x26 android 5.0/5.1 (Lolliop) 为例 1. source code • Kernel k ...
- Android USB audio on Android platform
这种是android手机为Host, audio设备为device. 以MSM8x26 android 5.0/5.1 (Lolliop) 为例1. source code •Kernelkernel ...
- Android USB Audio accessory设备
这个手机做device, audio accessory是Host. 以高通msm8x26(USB2.0) Lolliop android 5.0/5.1为例1 代码•Kernelkernel/dri ...
- Android usb audio信息获取(一)
android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...
- Android usb audio调用流程(二)
android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...
- Android usb audio录音(四)
android audio 生产者与消费者 简介 全面接触生产者/消费者问题是在操作系统原理中,并发性原理讨论的问题 生产者/消费者问题.最近的工作偏向音频,接着上一篇文章,用生产者,消费者模型来理解 ...
- Android Audio代码分析(2): AudioPoilicyService 启动
policy: 设备的选择 https://www.cxyzjd.com/article/VNanyesheshou/115659838 Android 音频源码分析--AudioTrack设备选择_ ...
- Android USB Accessory分析
转自:https://blog.csdn.net/yingzhao80/article/details/45511351 Android下USB Accessory的实现分析 摘要:本文介绍了USB ...
- android挂载usb设备,android usb挂载分析---MountService启动
在android usb挂载分析----vold启动,我们的vold模块已经启动了,通信的机制也已经建立起来了,接下来我们分析一下MountService的启动,也就是我们FrameWork层的启动, ...
最新文章
- 自动分析源代码,创建函数地图展示调用关系
- Transient关键字的使用
- Unity3D之预设
- symantec 操作 重叠vo_无关收购 谈谈赛门铁克的产品策略思路
- 遍历文件夹还原数据库SQL语句
- Hadoop入门(八)Mapreduce高级shuffle之Partitioner
- Oracle教程之oracle 给用户授权
- 基于php校园失物招领,校园失物招领系统设计
- Codeforces-Div312
- JSP实用教程 第三章 JSP内置对象
- ROS端口映射这样才正确
- 获取网站url ico小图标
- 平板游戏交互式设计的10大规则
- 戴尔微型计算机7050配置,小巧彪悍 戴尔 OptiPlex 7050 微型机评测
- android虚拟按键
- 美国参议员建议立法“黑掉国土安全部”
- 系统分析师-资料总结-中
- VB.net是个弥天大谎,VB.net已死(海康威视 SDK 开发有感)
- od使用的小tips
- Arcmap做地图要领总结