#endif
/**
- * \defgroup CtlPlugin_SDK External control plugin SDK
+ * \defgroup CtlPlugin_SDK External Control Plugin SDK
* \{
*/
/** Callback table of ext */
struct snd_ctl_ext_callback {
- void (*close)(snd_ctl_ext_t *ext); /* opt */
- void (*subscribe_events)(snd_ctl_ext_t *ext, int subscribe); /* opt */
- int (*elem_count)(snd_ctl_ext_t *ext); /* req */
- int (*elem_list)(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id); /* req */
- snd_ctl_ext_key_t (*find_elem)(snd_ctl_ext_t *ext, const snd_ctl_elem_id_t *id); /* req */
- void (*free_key)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key); /* opt */
+ /**
+ * close the control handle; optional
+ */
+ void (*close)(snd_ctl_ext_t *ext);
+ /**
+ * return the total number of elements; required
+ */
+ int (*elem_count)(snd_ctl_ext_t *ext);
+ /**
+ * return the element id of the given offset (array index); required
+ */
+ int (*elem_list)(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id);
+ /**
+ * convert the element id to a search key; required
+ */
+ snd_ctl_ext_key_t (*find_elem)(snd_ctl_ext_t *ext, const snd_ctl_elem_id_t *id);
+ /**
+ * the destructor of the key; optional
+ */
+ void (*free_key)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key);
+ /**
+ * get the attribute of the element; required
+ */
int (*get_attribute)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
- int *type, unsigned int *acc, unsigned int *count); /* req */
+ int *type, unsigned int *acc, unsigned int *count);
+ /**
+ * get the element information of integer type
+ */
int (*get_integer_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
long *imin, long *imax, long *istep);
+ /**
+ * get the element information of integer64 type
+ */
int (*get_integer64_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
int64_t *imin, int64_t *imax, int64_t *istep);
+ /**
+ * get the element information of enumerated type
+ */
int (*get_enumerated_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items);
+ /**
+ * get the name of the enumerated item
+ */
int (*get_enumerated_name)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int item,
char *name, size_t name_max_len);
+ /**
+ * read the current values of integer type
+ */
int (*read_integer)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value);
+ /**
+ * read the current values of integer64 type
+ */
int (*read_integer64)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int64_t *value);
+ /**
+ * read the current values of enumerated type
+ */
int (*read_enumerated)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items);
+ /**
+ * read the current values of bytes type
+ */
int (*read_bytes)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data,
size_t max_bytes);
+ /**
+ * read the current values of iec958 type
+ */
int (*read_iec958)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, snd_aes_iec958_t *iec958);
+ /**
+ * update the current values of integer type with the given values
+ */
int (*write_integer)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value);
+ /**
+ * update the current values of integer64 type with the given values
+ */
int (*write_integer64)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int64_t *value);
+ /**
+ * update the current values of enumerated type with the given values
+ */
int (*write_enumerated)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items);
+ /**
+ * update the current values of bytes type with the given values
+ */
int (*write_bytes)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data,
size_t max_bytes);
+ /**
+ * update the current values of iec958 type with the given values
+ */
int (*write_iec958)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, snd_aes_iec958_t *iec958);
+ /**
+ * subscribe/unsubscribe the event notification; optional
+ */
+ void (*subscribe_events)(snd_ctl_ext_t *ext, int subscribe);
+ /**
+ * read a pending notification event; optional
+ */
int (*read_event)(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id, unsigned int *event_mask);
+ /**
+ * return the number of poll descriptors; optional
+ */
int (*poll_descriptors_count)(snd_ctl_ext_t *ext);
+ /**
+ * fill the poll descriptors; optional
+ */
int (*poll_descriptors)(snd_ctl_ext_t *ext, struct pollfd *pfds, unsigned int space);
+ /**
+ * mangle the revents of poll descriptors
+ */
int (*poll_revents)(snd_ctl_ext_t *ext, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
};
-enum snd_ctl_ext_access_t {
+/**
+ * The access type bits stored in get_attribute callback
+ */
+typedef enum snd_ctl_ext_access {
SND_CTL_EXT_ACCESS_READ = (1<<0),
SND_CTL_EXT_ACCESS_WRITE = (1<<1),
SND_CTL_EXT_ACCESS_READWRITE = (3<<0),
SND_CTL_EXT_ACCESS_VOLATILE = (1<<2),
SND_CTL_EXT_ACCESS_INACTIVE = (1<<8),
-};
+} snd_ctl_ext_access_t;
+/**
+ * find_elem callback returns this if no matching control element is found
+ */
#define SND_CTL_EXT_KEY_NOT_FOUND (snd_ctl_ext_key_t)(-1)
int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode);
+/**
+ * \file control/control_ext.c
+ * \ingroup CtlPlugin_SDK
+ * \brief External Control Plugin SDK
+ * \author Takashi Iwai <tiwai@suse.de>
+ * \date 2005
+ */
/*
* Control Interface - External Control Plugin SDK
*
.poll_revents = snd_ctl_ext_poll_revents,
};
+/*
+ * Exported functions
+ */
+
+/*! \page ctl_external_plugins External Control Plugin SDK
+
+\section ctl_externals External Control Plugins
+
+The external plugins are implemented in a shared object file located
+at /usr/lib/alsa-lib (the exact location depends on the build option
+and asoundrc configuration). It has to be the file like
+libasound_module_ctl_MYPLUGIN.so, where MYPLUGIN corresponds to your
+own plugin name.
+
+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:
+\code
+int (snd_ctl_t **phandle, const char *name, snd_config_t *root,
+ snd_config_t *conf, int mode)
+\endcode
+The first argument, phandle, is the pointer to store the resultant control
+handle. The arguments name, root and mode are the parameters
+to be passed to the plugin constructor. The conf is the configuration
+tree for the plugin. The arguments above are defined in the macro
+itself, so don't use variables with the same names to shadow
+parameters.
+
+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:
+\code
+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);
+\endcode
+
+Read the codes in alsa-plugins package for the real examples.
+
+
+\section ctl_ext_impl Implementation of External Control Plugins
+
+The following fields have to be filled in external control record before calling
+#snd_ctl_ext_create() : version, card_idx, id, name, longname, mixername, poll_fd and callback.
+Otherfields are optional and should be initialized with zero.
+
+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 <i>copy</i> 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.
+
+\section ctl_ext_impl Callback Functions of External Control Plugins
+
+The callback functions in #snd_ctl_ext_callback_t define the real
+behavior of the driver. There are many callbacks but many of them are optional.
+
+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 iface, name and index) in return via the
+standard control API functions like #snd_ctl_elem_id_set_ifarce,
+#snd_ctl_elem_id_set_name and #snd_ctl_elem_id_set_index, etc. The callbacks should
+return 0 if successful, or a negative error code.
+
+The find_elem callback is used to convert the given control element ID to the
+certain key value for the faster access to get, read and write callbacks.
+The key type is alias of unsigned long, so you can assign some static number
+(e.g. index of the array) to this value of the corresponding element, or
+assign the pointer (cast to #snd_ctl_ext_key_t). When no key is defined or found,
+return #SND_CTL_EXT_KEY_NOT_FOUND. This callback is (very likely) required
+if you use get, read and write callbacks as follows.
+If you need to create a record dynamically (e.g. via malloc) at each find_elem call,
+the allocated record can be released with the optional free_key callback.
+
+The get_attribute is a mandatory callback, which returns the attribute of the
+control element given via a key value (converted with find_elem callback).
+It must fill the control element type (#snd_ctl_elem_type_t), the access type
+(#snd_ctl_ext_access_t), and the count (element array size). The callback returns
+0 if successful, or a negative error code, as usual.
+
+The get_integer_info, get_integetr64_info and get_enumerated_info callbacks are called
+to return the information of the given control element for each element type.
+For integer and integer64 types, the callbacks need to fill the minimal (imin),
+maximal (imax) and the step (istep) values of the control. For the enumerated type,
+the number of enum items must be filled. Additionally, the enum control has to define
+get_enumerated_name callback to store the name of the enumerated item of the given control
+element. All functions return 0 if successful, or a negative error code.
+
+For reading the current values of a control element, read_integer, read_integer64,
+read_enumerated, read_bytes and read_iec958 callbacks are called depending on the
+element type. These callbacks have to fill the current values of the element in return.
+Note that a control element can be an array. If it contains more than one values
+(i.e. the count value in get_attribute callback is more than 1), <i>all</i> values
+must be filled on the given value pointer as an array. Also, note that the boolean type
+is handled as integer here (although boolean type doesn't need to define the corresponding
+info callback since it's obvious). These callbacks return 0 if successful, or
+a negative error code.
+
+For writing the current values, write_integer, write_integer64, write_bytes, and
+write_iec958 callbacks are called as well as for read. The callbacks should check the
+current values and compare with the given values. If they are identical, the callbacks
+should do nothing and return 0. If they differ, update the current values and return 1,
+instead. For any errors, return a negative error code.
+
+The subscribe_events callback is called when the application subscribes or cancels
+the event notifications (e.g. through mixer API). The current value of event
+subscription is kept in the subscribed field.
+The read_event callback is called for reading a pending notification event.
+The callback needs to fill the event_mask value, a bit-field defined as SND_CTL_EVENT_MASK_XXX.
+If no event is pending, return -EAGAIN. These two callbacks are optional.
+
+The poll_descriptors_count and poll_descriptors callbacks are used to return
+the poll descriptor(s) via callbacks. As already mentioned, if the callback cannot
+set the static poll_fd, you can define these callbacks to return dynamically.
+Also, when multiple poll descriptors are required, use these callbacks.
+The poll_revents callback is used for handle poll revents.
+
+*/
+
/**
* \brief Create an external control plugin instance
* \param ext the plugin handle