The entry point of the plugin is defined via SND_CTL_PLUGIN_DEFINE_FUNC() macro. This macro defines the function with a proper name to be referred from alsa-lib. The function takes the following 5 arguments:
int (snd_ctl_t **phandle, const char *name, snd_config_t *root, snd_config_t *conf, int mode)
After parsing the configuration parameters in the given conf tree, usually you will call the external plugin API function snd_ctl_ext_create(). The control handle must be filled *phandle in return. Then this function must return either a value 0 when succeeded, or a negative value as the error code.
Finally, add SND_CTL_PLUGIN_SYMBOL() with the name of your plugin as the argument at the end. This defines the proper versioned symbol as the reference.
The typical code would look like below:
struct myctl_info { snd_ctl_ext_t ext; int my_own_data; ... }; SND_CTL_PLUGIN_DEFINE_FUNC(myctl) { snd_config_iterator_t i, next; struct myctl_info *myctl; int err; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); const char *id; if (snd_config_get_id(n, &id) < 0) continue; if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0) continue; if (strcmp(id, "my_own_parameter") == 0) { .... continue; } SNDERR("Unknown field %s", id); return -EINVAL; } myctl = calloc(1, sizeof(*myctl)); if (myctl == NULL) return -ENOMEM; myctl->ext.version = SND_CTL_EXT_VERSION; myctl->ext.card_idx = 0; strcpy(myctl->ext.id, "Myctl"); strcpy(myctl->ext.name, "My Control"); strcpy(myctl->ext.longname, "My External Control for Foobar"); strcpy(myctl->ext.mixername, "My Control"); myctl->ext.callback = &my_own_callback; myctl->ext.private_data = myctl; .... err = snd_pcm_extplug_create(&myctl->ext, name, mode); if (err < 0) { myctl_free(myctl); return err; } *phandle = myctl->ext.handle; return 0; } SND_CTL_PLUGIN_SYMBOL(myctl);
Read the codes in alsa-plugins package for the real examples.
The constant SND_CTL_EXT_VERSION must be passed to the version field for the version check in alsa-lib. The card_idx field specifies the card index of this control. [FIXME: solve confliction of card index in alsa-lib?]
The id, name, longname and mixername fields are the strings shown in the card_info inqurirys. They are the char arrays, so you have to copy strings to these fields.
The callback field contains the table of callback functions for this plugin (defined as snd_ctl_ext_callback_t). The poll_fd can be used to specify the poll file descriptor for this control. Set -1 if not available. Alternatively, you can define poll_descriptors_count and poll_descriptors callbacks in the callback table for handling the poll descriptor(s) dynamically after the creation of plugin instance.
The driver can set an arbitrary value (pointer) to private_data field to refer its own data in the callbacks.
The rest fields are filled by snd_ctl_ext_create(). The handle field is the resultant PCM handle. The others are the current status of the PCM.
The close callback is called when the PCM is closed. If the plugin allocates private resources, this is the place to release them again. This callback is optional.
The elem_count and elem_list callbacks are mandatory. The elem_count returns the total number of control elements. The elem_list returns the control element ID of the corresponding element offset (the offset is from 0 to elem_count - 1). The id field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to all zero in prior to elem_list callback. The callback has to fill the necessary field (typically i="qiid field is initialized to