一.
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()函數。