tinymix
源码浅析
针对上篇文章中的kcontrol与ucontrol的区别,在此粘上源码,主要负责实现应用层至底层的参数传递,ucontrol的数据类型为snd_ctl_elem_value,结构体具体如下
struct snd_ctl_elem_value {
916 struct snd_ctl_elem_id id; /* W: element ID */
917 unsigned int indirect: 1; /* W: indirect access - obsoleted */
918 union {
919 union {
920 long value[128];
921 long *value_ptr; /* obsoleted */
922 } integer;
923 union {
924 long long value[64];
925 long long *value_ptr; /* obsoleted */
926 } integer64;
927 union {
928 unsigned int item[128];
929 unsigned int *item_ptr; /* obsoleted */
930 } enumerated;
931 union {
932 unsigned char data[512];
933 unsigned char *data_ptr; /* obsoleted */
934 } bytes;
935 struct snd_aes_iec958 iec958;
936 } value; /* RO */
937 struct timespec tstamp;
938 unsigned char reserved[128-sizeof(struct timespec)];
939 };
940
420 int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
421 {
422 struct snd_ctl_elem_value ev;
423 int ret;
424
425 if (!ctl || (id >= ctl->info->count))
426 return -EINVAL;
427
428 memset(&ev, 0, sizeof(ev));
429 ev.id.numid = ctl->info->id.numid;
430 ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
431 if (ret < 0)
432 return ret;
433
434 switch (ctl->info->type) {
435 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
436 ev.value.integer.value[id] = !!value;
437 break;
438
439 case SNDRV_CTL_ELEM_TYPE_INTEGER:
440 ev.value.integer.value[id] = value;
441 break;
442
443 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
444 ev.value.enumerated.item[id] = value;
445 break;
446
447 case SNDRV_CTL_ELEM_TYPE_BYTES:
448 ev.value.bytes.data[id] = value;
449 break;
450
451 default:
452 return -EINVAL;
453 }
454
455 return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
456 }
usage
static void usage (void) {
fprintf(stderr,
"tinymix [options] [control name/#] [value to set]\n"
" options:\n"
" --device|-D <card#> - use the given card # instead of 0.\n"
" --all-values|-a - show all possible values/ranges for control.\n"
" --tabs-only|-t - separate all output columns/values with tabs.\n"
" --value-only|-v - show only the value for the selected control.\n"
);
}
触发kcontrol回调流程
main
->tinymix_set_value
->mixer_ctl_set_value
->ioctl
->snd_ctl_elem_write_user --内核钩子函数
->snd_ctl_elem_write
->kcontrol中的put回调函数,源码如下
static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
struct snd_ctl_elem_value *control)
{
struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd;
unsigned int index_offset;
int result;
down_read(&card->controls_rwsem);
kctl = snd_ctl_find_id(card, &control->id);
if (kctl == NULL) {
result = -ENOENT;
} else {
index_offset = snd_ctl_get_ioff(kctl, &control->id);
vd = &kctl->vd[index_offset];
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
kctl->put == NULL ||
(file && vd->owner && vd->owner != file)) {
result = -EPERM;
} else {
snd_ctl_build_ioff(&control->id, kctl, index_offset);
//此处回调kcontrol的put回调函数
result = kctl->put(kctl, control);
}
if (result > 0) {
struct snd_ctl_elem_id id = control->id;
up_read(&card->controls_rwsem);
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
return 0;
}
}
up_read(&card->controls_rwsem);
return result;
}