一.
usb audio 在hal层中有单独的so文件,例如audio.usb.8909.so, 在创建AudioPolicyManager的时候会Load 该module。hal层中的文件都在hardware/libhardware/modules/usbaudio/目录下:
usb audio的播放流程和正常的播放流程并无不同,最主要的差异在于,音频是从AudioFlinger通过USB hal送到kernel中的。如下图:
在AudioFinger中调用open_output_stream的时候,调用的是usb hal文件中的open_output_stream, 具体定义在audio_hw.c中, hal层中的文件都在hardware/libhardware/modules/usbaudio/目录下。可以看到,和primary hal一样,它也提供标准的输入输出设备操作接口函数,调用方法和primary hal一样。
1 static int adev_open(const hw_module_t *module, const char *name,
2 hw_device_t **device)
3 {
4 adev->device.common.tag = HARDWARE_DEVICE_TAG;
5 adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
6 adev->device.common.module = (struct hw_module_t *)module;
7 adev->device.common.close = adev_close;
8
9 adev->device.init_check = adev_init_check;
10 adev->device.set_voice_volume = adev_set_voice_volume;
11 adev->device.set_master_volume = adev_set_master_volume;
12 adev->device.get_master_volume = adev_get_master_volume;
13 adev->device.set_master_mute = adev_set_master_mute;
14 adev->device.get_master_mute = adev_get_master_mute;
15 adev->device.set_mode = adev_set_mode;
16 adev->device.set_mic_mute = adev_set_mic_mute;
17 adev->device.get_mic_mute = adev_get_mic_mute;
18 adev->device.set_parameters = adev_set_parameters;
19 adev->device.get_parameters = adev_get_parameters;
20 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
21 adev->device.open_output_stream = adev_open_output_stream;
22 adev->device.close_output_stream = adev_close_output_stream;
23 adev->device.open_input_stream = adev_open_input_stream;
24 adev->device.close_input_stream = adev_close_input_stream;
25 adev->device.dump = adev_dump;
26 }
同样的,对于播放来说,它提供的也是标准的操作输出设备的接口函数:
1 static int adev_open_output_stream(struct audio_hw_device *dev,
2 audio_io_handle_t handle,
3 audio_devices_t devices,
4 audio_output_flags_t flags,
5 struct audio_config *config,
6 struct audio_stream_out **stream_out,
7 const char *address __unused)
8 {
9 out->stream.common.get_sample_rate = out_get_sample_rate;
10 out->stream.common.set_sample_rate = out_set_sample_rate;
11 out->stream.common.get_buffer_size = out_get_buffer_size;
12 out->stream.common.get_channels = out_get_channels;
13 out->stream.common.get_format = out_get_format;
14 out->stream.common.set_format = out_set_format;
15 out->stream.common.standby = out_standby;
16 out->stream.common.dump = out_dump;
17 out->stream.common.set_parameters = out_set_parameters;
18 out->stream.common.get_parameters = out_get_parameters;
19 out->stream.common.add_audio_effect = out_add_audio_effect;
20 out->stream.common.remove_audio_effect = out_remove_audio_effect;
21 out->stream.get_latency = out_get_latency;
22 out->stream.set_volume = out_set_volume;
23 out->stream.write = out_write;
24 out->stream.get_render_position = out_get_render_position;
25 out->stream.get_presentation_position = out_get_presentation_position;
26 out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
27 }
我们重点看看out_write接口函数, AudioFlinger通过该接口函数,将音频数据从framework层搬运到hal层再送到Kernel中。
1 static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
2 {
3 /*如果暂停,则使能输出, 这里是调用pcm_open来实现的*/
4 if (out->standby) {
5 ret = start_output_stream(out);
6 if (ret != 0) {
7 pthread_mutex_unlock(&out->dev->lock);
8 goto err;
9 }
10 out->standby = false;
11 }
12
13 /*调用pcm_write写入数据*/
14 if (write_buff != NULL && num_write_buff_bytes != 0) {
15 proxy_write(&out->proxy, write_buff, num_write_buff_bytes);
16 }
17 }
可以看到,最终都是通过pcm接口函数来操作的。所以,在kernel侧对于USB audio是创建了对应的pcm设备的。
二.
kernel侧的USB audio驱动是在kernel/sound/usb/目录下,以card.c文件为入口查看:
在cards文件中,初始化的时候,注册了一个USB驱动, 将此驱动加入到USB驱动链表中,当有USB设备插入时,USB Host回去扫描链表,将驱动和设备进行匹配,匹配成功后,就会触发
probe函数的调用, 驱动创建成功后,在/sys/bus/usb/drivers/目录下面,可以看到snd-usb-audio目录。
1 static struct usb_driver usb_audio_driver = {
2 .name = "snd-usb-audio",
3 .probe = usb_audio_probe,
4 .disconnect = usb_audio_disconnect,
5 .suspend = usb_audio_suspend,
6 .resume = usb_audio_resume,
7 .id_table = usb_audio_ids,
8 .supports_autosuspend = 1,
9 };
在probe函数中执行了声卡的创建和音频接口的创建工作, 看下创建pcm函数的地方,其中stream的值根据USB描述符中USB的类型是USB_DIR_IN,则赋值为CAPTURE, USB_DIR_OUT
则赋值为PLAYBACK
1 int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
2 int stream,
3 struct audioformat *fp)
4 {
5 /*创建pcm*/
6 err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
7 stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
8 stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
9 &pcm);
10
11 /*初始化stream接口函数*/
12 snd_usb_init_substream(as, stream, fp);
13 }
snd_pcm_new()函数为标准的创建pcm设备的接口函数,该接口函数中根据stream的类型会分别创建playback_stream和capture_stream,并分别创建对应的playback的pcm接口和capture的接口:
标准的pcm接口操作函数为:
1 const struct file_operations snd_pcm_f_ops[2] = {
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_usb_init_substream()函数:
1 static void snd_usb_init_substream(struct snd_usb_stream *as,
2 int stream,
3 struct audioformat *fp)
4 {
5 struct snd_usb_substream *subs = &as->substream[stream];
6
7 INIT_LIST_HEAD(&subs->fmt_list);
8 spin_lock_init(&subs->lock);
9
10 subs->stream = as; //赋值为对应的usb_stream
11 subs->direction = stream; //方向取决于usb类型为usb_dir_in还是usb_dir_out
12 subs->dev = as->chip->dev;
13 subs->txfr_quirk = as->chip->txfr_quirk;
14 subs->speed = snd_usb_get_speed(subs->dev);
15 subs->pkt_offset_adj = 0;
16
17 snd_usb_set_pcm_ops(as->pcm, stream); //设置stream的操作接口函数
18
19 list_add_tail(&fp->list, &subs->fmt_list);
20 subs->formats |= fp->formats;
21 subs->num_formats++;
22 subs->fmt_type = fp->fmt_type;
23 subs->ep_num = fp->endpoint;
24 if (fp->channels > subs->channels_max)
25 subs->channels_max = fp->channels;
26 }
其中最重要的是snd_usb_set_pcm_ops()函数,它设置了pcm_substream的操作接口函数:
1 void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream)
2 {
3 snd_pcm_set_ops(pcm, stream,
4 stream == SNDRV_PCM_STREAM_PLAYBACK ?
5 &snd_usb_playback_ops : &snd_usb_capture_ops);
6 }
1 static struct snd_pcm_ops snd_usb_playback_ops = {
2 .open = snd_usb_playback_open,
3 .close = snd_usb_playback_close,
4 .ioctl = snd_pcm_lib_ioctl,
5 .hw_params = snd_usb_hw_params,
6 .hw_free = snd_usb_hw_free,
7 .prepare = snd_usb_pcm_prepare,
8 .trigger = snd_usb_substream_playback_trigger,
9 .pointer = snd_usb_pcm_pointer,
10 .page = snd_pcm_lib_get_vmalloc_page,
11 .mmap = snd_pcm_lib_mmap_vmalloc,
12 };
13
14 static struct snd_pcm_ops snd_usb_capture_ops = {
15 .open = snd_usb_capture_open,
16 .close = snd_usb_capture_close,
17 .ioctl = snd_pcm_lib_ioctl,
18 .hw_params = snd_usb_hw_params,
19 .hw_free = snd_usb_hw_free,
20 .prepare = snd_usb_pcm_prepare,
21 .trigger = snd_usb_substream_capture_trigger,
22 .pointer = snd_usb_pcm_pointer,
23 .page = snd_pcm_lib_get_vmalloc_page,
24 .mmap = snd_pcm_lib_mmap_vmalloc,
25 };
上面函数给pcm->substream->ops赋值,根据stream类型,分别赋值为snd_usb_playback_ops 或者 snd_usb_capture_ops:
类如,如果应用层调用pcm_write接口函数写入数据,则其调用的流程如下:
pcm_write调用的是ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x), 对应到kernel中,调用的就是上面的snd_pcm_playback_ioctl()函数:
1 static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
2 unsigned long arg)
3 {
4 return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
5 (void __user *)arg);
6 }
7
9 static int snd_pcm_playback_ioctl1(struct file *file,
10 struct snd_pcm_substream *substream,
11 unsigned int cmd, void __user *arg)
12 {
13 switch (cmd) {
14 case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
15 {
16 struct snd_xferi xferi;
17 struct snd_xferi __user *_xferi = arg;
18 struct snd_pcm_runtime *runtime = substream->runtime;
19 snd_pcm_sframes_t result;
20 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
21 return -EBADFD;
22 if (put_user(0, &_xferi->result))
23 return -EFAULT;
24 if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
25 return -EFAULT;
26 result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
27 __put_user(result, &_xferi->result);
28 return result < 0 ? result : 0;
29 }
30 }
31 }
32
33 snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
34 {
35 return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock,
36 snd_pcm_lib_write_transfer);
37 }
38
39 static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
40 unsigned long data,
41 snd_pcm_uframes_t size,
42 int nonblock,
43 transfer_f transfer)
44 {
45 err = transfer(substream, appl_ofs, data, offset, frames);
46 }
47
48 static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
49 unsigned int hwoff,
50 unsigned long data, unsigned int off,
51 snd_pcm_uframes_t frames)
52 {
53 struct snd_pcm_runtime *runtime = substream->runtime;
54 int err;
55 char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
56 if (substream->ops->copy) {
57 if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
58 return err;
59 } else {
60 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
61 if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
62 return -EFAULT;
63 }
64 return 0;
65 }
最终,如果定义了substream->ops->copy接口函数,则会调用substream->ops->copy执行数据的传输,否则,就将数据放到substream->runtime->dma_area + frames_to_bytes(runtime, hwoff) 地址处,在这里,是没有定义copy函数的,所以pcm_write写下来的数据都是放在substream->runtime->dma_area里面。
我们知道usb数据传输是通过urb完成的,程序中将数据拷贝到urb中,再提交给主控制器,由主控制器来进行实际的数据传输,这里也是一样的。
在hw_params设置参数的函数中调用snd_usb_init_substream_urbs()为substream分配初始化urb.
1 int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
2 unsigned int period_bytes,
3 unsigned int rate,
4 unsigned int frame_bits)
5 {
6 /*根据上面计算的urb的个数和大小,来创建urb*/
7 /* allocate and initialize data urbs */
8 for (i = 0; i < subs->nurbs; i++) {
9 struct snd_urb_ctx *u = &subs->dataurb[i];
10 u->index = i;
11 u->subs = subs;
12 u->packets = (i + 1) * total_packs / subs->nurbs
13 - i * total_packs / subs->nurbs;
14 u->buffer_size = maxsize * u->packets;
15 if (subs->fmt_type == UAC_FORMAT_TYPE_II)
16 u->packets++; /* for transfer delimiter */
17 u->urb = usb_alloc_urb(u->packets, GFP_KERNEL);
18 if (!u->urb)
19 goto out_of_memory;
20 u->urb->transfer_buffer =
21 usb_alloc_coherent(subs->dev, u->buffer_size,
22 GFP_KERNEL, &u->urb->transfer_dma);
23 if (!u->urb->transfer_buffer)
24 goto out_of_memory;
25 u->urb->pipe = subs->datapipe;
26 u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
27 u->urb->interval = 1 << subs->datainterval;
28 u->urb->context = u;
29 u->urb->complete = snd_complete_urb; //urb传输完成后会调用此函数
30 }
31 }
函数一开始的大段程序,都是根据当前写入的buffer大小,采样率,采样精度,声道数,来计算需要的urb的大小和个数,之后就开始创建urb,注意到最后一个complete成员,这个是个回调函数数,在urb传输完成后会调用此函数,在这个函数中会重新准备urb中的数据,继续提交urb给USB总控制器。
1 static void snd_complete_urb(struct urb *urb)
2 {
3 struct snd_urb_ctx *ctx = urb->context;
4 struct snd_usb_substream *subs = ctx->subs;
5 struct snd_pcm_substream *substream = ctx->subs->pcm_substream;
6 int err = 0;
7
8 /*准备urb中的数据,继续提交urb*/
9 if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) ||
10 !subs->running || /* can be stopped during retire callback */
11 (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 ||
12 (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
13 clear_bit(ctx->index, &subs->active_mask);
14 if (err < 0) {
15 snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err);
16 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
17 }
18 }
19 }
我们整理下整个播放流程:
hal层中:
开始播放:
out_write(audio_hw.c) ==>
start_output_stream(audio_hw.c) ==>
proxy_open(alsa_device_proxy.c) ==>
pcm_open()
播放:
out_write(audio_hw.c) ==>
proxy_write(alsa_device_proxy.c) ==>
pcm_write()
暂停和停止播放:
out_standby(audio_hw.c) ==>
proxy_close(alsa_device_proxy.c) ==>
pcm_close()
tinyalsa层中:
开始播放:
pcm_open(pcm.c) ==>
open(fn, O_RDWR);
ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms);
ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams);
播放:
pcm_write(pcm.c) ==>
/*第一次执行pcm_prepare*/
pcm_prepare(pcm);
ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x);
暂停和停止播放:
pcm_close(pcm.c) ==>
close(pcm->fd);
kernel中:
函数中调用prepare_playback_urb()准备urb中的数据,然后叫urb提交给USB总控制器进行数据传输。其实,大概可以想象得到,在prepare_playback_urb()中,我们是将 上面存放音频数据的
substream->runtime->dma_area中的数据拷贝到urb的buffer中。我们看看prepare_playback_urb()函数。