From 7651690858a8b026f2a4447e804ee8bf1a155ebb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 May 2005 09:42:01 +0000 Subject: [PATCH] Fix documentation of external PCM plugin SDK Fix documentation of external PCM plugin SDK. --- doc/doxygen.cfg | 3 + include/pcm_external.h | 10 +++ include/pcm_extplug.h | 42 ++++++++++-- include/pcm_ioplug.h | 63 ++++++++++++------ src/pcm/pcm_extplug.c | 145 +++++++++++++++++++++++++++++++++++++++-- src/pcm/pcm_ioplug.c | 82 ++++++++++++++++++++++- 6 files changed, 313 insertions(+), 32 deletions(-) diff --git a/doc/doxygen.cfg b/doc/doxygen.cfg index 5f830b1a..6ac2688b 100644 --- a/doc/doxygen.cfg +++ b/doc/doxygen.cfg @@ -23,6 +23,9 @@ INPUT = index.doxygen \ ../include/seq_event.h \ ../include/seqmid.h \ ../include/seq_midi_event.h \ + ../include/pcm_external.h \ + ../include/pcm_extplug.h \ + ../include/pcm_ioplug.h \ ../include/conv.h \ ../include/instr.h \ ../src/error.c \ diff --git a/include/pcm_external.h b/include/pcm_external.h index 54810535..57504188 100644 --- a/include/pcm_external.h +++ b/include/pcm_external.h @@ -37,9 +37,19 @@ extern "C" { * \{ */ +/** + * Define the object entry for external PCM plugins + */ #define SND_PCM_PLUGIN_ENTRY(name) _snd_pcm_##name##_open + +/** + * Define the symbols of the given plugin with versions + */ #define SND_PCM_PLUGIN_SYMBOL(name) SND_DLSYM_BUILD_VERSION(SND_PCM_PLUGIN_ENTRY(name), SND_PCM_DLSYM_VERSION); +/** + * Define the plugin + */ #define SND_PCM_PLUGIN_DEFINE_FUNC(plugin) \ int SND_PCM_PLUGIN_ENTRY(plugin) (snd_pcm_t **pcmp, const char *name,\ snd_config_t *root, snd_config_t *conf, \ diff --git a/include/pcm_extplug.h b/include/pcm_extplug.h index 566c18ef..7a822d8f 100644 --- a/include/pcm_extplug.h +++ b/include/pcm_extplug.h @@ -1,3 +1,12 @@ +/** + * \file include/pcm_extplug.h + * \brief External Filter-Plugin SDK + * \author Takashi Iwai + * \date 2005 + * + * External Filter-Plugin SDK + */ + /* * ALSA external PCM plugin SDK (draft version) * @@ -22,6 +31,13 @@ #ifndef __ALSA_PCM_EXTPLUG_H #define __ALSA_PCM_EXTPLUG_H +/** + * \defgroup PCM_ExtPlug External Filter plugin SDK + * \ingroup Plugin_SDK + * See the \ref pcm page for more details. + * \{ + */ + /** hw constraints for extplug */ enum { SND_PCM_EXTPLUG_HW_FORMAT, /**< format */ @@ -29,23 +45,28 @@ enum { SND_PCM_EXTPLUG_HW_PARAMS /**< max number of hw constraints */ }; +/** Handle of external filter plugin */ typedef struct snd_pcm_extplug snd_pcm_extplug_t; +/** Callback table of extplug */ typedef struct snd_pcm_extplug_callback snd_pcm_extplug_callback_t; -/** +/* * Protocol version */ -#define SND_PCM_EXTPLUG_VERSION_MAJOR 1 -#define SND_PCM_EXTPLUG_VERSION_MINOR 0 -#define SND_PCM_EXTPLUG_VERSION_TINY 0 +#define SND_PCM_EXTPLUG_VERSION_MAJOR 1 /**< Protocol major version */ +#define SND_PCM_EXTPLUG_VERSION_MINOR 0 /**< Protocol minor version */ +#define SND_PCM_EXTPLUG_VERSION_TINY 0 /**< Protocol tiny version */ +/** + * Filter-plugin protocol version + */ #define SND_PCM_EXTPLUG_VERSION ((SND_PCM_EXTPLUG_VERSION_MAJOR<<16) |\ (SND_PCM_EXTPLUG_VERSION_MINOR<<8) |\ (SND_PCM_EXTPLUG_VERSION_TINY)) -/** handle of extplug */ +/** Handle of extplug */ struct snd_pcm_extplug { /** - * protocol version; SND_PCM_EXTPLUG_VERSION must be filled here + * protocol version; #SND_PCM_EXTPLUG_VERSION must be filled here * before calling #snd_pcm_extplug_create() */ unsigned int version; @@ -99,7 +120,7 @@ struct snd_pcm_extplug { unsigned int slave_channels; }; -/** callback table of extplug */ +/** Callback table of extplug */ struct snd_pcm_extplug_callback { /** * transfer between source and destination; this is a required callback @@ -143,15 +164,22 @@ int snd_pcm_extplug_set_param_minmax(snd_pcm_extplug_t *extplug, int type, unsig int snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list); int snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max); +/** + * set the parameter constraint with a single value + */ static inline int snd_pcm_extplug_set_param(snd_pcm_extplug_t *extplug, int type, unsigned int val) { return snd_pcm_extplug_set_param_list(extplug, type, 1, &val); } +/** + * set the parameter constraint for slave PCM with a single value + */ static inline int snd_pcm_extplug_set_slave_param(snd_pcm_extplug_t *extplug, int type, unsigned int val) { return snd_pcm_extplug_set_slave_param_list(extplug, type, 1, &val); } +/** \} */ #endif /* __ALSA_PCM_EXTPLUG_H */ diff --git a/include/pcm_ioplug.h b/include/pcm_ioplug.h index 5dee834d..58f97be6 100644 --- a/include/pcm_ioplug.h +++ b/include/pcm_ioplug.h @@ -1,5 +1,14 @@ +/** + * \file include/pcm_ioplug.h + * \brief External I/O-Plugin SDK + * \author Takashi Iwai + * \date 2005 + * + * External I/O-Plugin SDK + */ + /* - * ALSA external PCM plugin SDK (draft version) + * ALSA external PCM plugin SDK * * Copyright (c) 2005 Takashi Iwai * @@ -22,6 +31,13 @@ #ifndef __ALSA_PCM_IOPLUG_H #define __ALSA_PCM_IOPLUG_H +/** + * \defgroup PCM_IOPlug External I/O plugin SDK + * \ingroup Plugin_SDK + * See the \ref pcm page for more details. + * \{ + */ + /** hw constraints for ioplug */ enum { SND_PCM_IOPLUG_HW_ACCESS = 0, /**< access type */ @@ -34,7 +50,9 @@ enum { SND_PCM_IOPLUG_HW_PARAMS /**< max number of hw constraints */ }; +/** I/O plugin handle */ typedef struct snd_pcm_ioplug snd_pcm_ioplug_t; +/** Callback table of ioplug */ typedef struct snd_pcm_ioplug_callback snd_pcm_ioplug_callback_t; /** @@ -42,20 +60,23 @@ typedef struct snd_pcm_ioplug_callback snd_pcm_ioplug_callback_t; */ #define SND_PCM_IOPLUG_FLAG_LISTED (1<<0) /* list up this PCM */ -/** +/* * Protocol version */ -#define SND_PCM_IOPLUG_VERSION_MAJOR 1 -#define SND_PCM_IOPLUG_VERSION_MINOR 0 -#define SND_PCM_IOPLUG_VERSION_TINY 0 +#define SND_PCM_IOPLUG_VERSION_MAJOR 1 /**< Protocol major version */ +#define SND_PCM_IOPLUG_VERSION_MINOR 0 /**< Protocol minor version */ +#define SND_PCM_IOPLUG_VERSION_TINY 0 /**< Protocol tiny version */ +/** + * IO-plugin protocol version + */ #define SND_PCM_IOPLUG_VERSION ((SND_PCM_IOPLUG_VERSION_MAJOR<<16) |\ (SND_PCM_IOPLUG_VERSION_MINOR<<8) |\ (SND_PCM_IOPLUG_VERSION_TINY)) -/** handle of ioplug */ +/** Handle of ioplug */ struct snd_pcm_ioplug { /** - * protocol version; SND_PCM_IOPLUG_VERSION must be filled here + * protocol version; #SND_PCM_IOPLUG_VERSION must be filled here * before calling #snd_pcm_ioplug_create() */ unsigned int version; @@ -80,21 +101,21 @@ struct snd_pcm_ioplug { */ snd_pcm_t *pcm; - snd_pcm_stream_t stream; /* stream direcion; read-only */ - snd_pcm_state_t state; /* current PCM state; read-only */ - volatile snd_pcm_uframes_t appl_ptr; /* application pointer; read-only */ - volatile snd_pcm_uframes_t hw_ptr; /* hw pointer; read-only */ - int nonblock; /* non-block mode; read-only */ - - snd_pcm_access_t access; /* access type; filled after hw_params is called */ - snd_pcm_format_t format; /* format; filled after hw_params is called */ - unsigned int channels; /* channels; filled after hw_params is called */ - unsigned int rate; /* rate; filled after hw_params is called */ - snd_pcm_uframes_t period_size; /* period size; filled after hw_params is called */ - snd_pcm_uframes_t buffer_size; /* buffer size; filled after hw_params is called */ + snd_pcm_stream_t stream; /**< stream direcion; read-only */ + snd_pcm_state_t state; /**< current PCM state; read-only */ + volatile snd_pcm_uframes_t appl_ptr; /**< application pointer; read-only */ + volatile snd_pcm_uframes_t hw_ptr; /**< hw pointer; read-only */ + int nonblock; /**< non-block mode; read-only */ + + snd_pcm_access_t access; /**< access type; filled after hw_params is called */ + snd_pcm_format_t format; /**< PCM format; filled after hw_params is called */ + unsigned int channels; /**< number of channels; filled after hw_params is called */ + unsigned int rate; /**< rate; filled after hw_params is called */ + snd_pcm_uframes_t period_size; /**< period size; filled after hw_params is called */ + snd_pcm_uframes_t buffer_size; /**< buffer size; filled after hw_params is called */ }; -/** callback table of ioplug */ +/** Callback table of ioplug */ struct snd_pcm_ioplug_callback { /** * start the PCM; required @@ -183,4 +204,6 @@ void snd_pcm_ioplug_params_reset(snd_pcm_ioplug_t *io); int snd_pcm_ioplug_set_param_minmax(snd_pcm_ioplug_t *io, int type, unsigned int min, unsigned int max); int snd_pcm_ioplug_set_param_list(snd_pcm_ioplug_t *io, int type, unsigned int num_list, const unsigned int *list); +/** \} */ + #endif /* __ALSA_PCM_IOPLUG_H */ diff --git a/src/pcm/pcm_extplug.c b/src/pcm/pcm_extplug.c index e51800b0..36d4d248 100644 --- a/src/pcm/pcm_extplug.c +++ b/src/pcm/pcm_extplug.c @@ -433,7 +433,96 @@ static snd_pcm_ops_t snd_pcm_extplug_ops = { * Exported functions */ -/*! \page pcm_external_plugins +/*! \page pcm_external_plugins PCM External Plugin SDK + +\section pcm_externals External 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_pcm_MYPLUGIN.so, where MYPLUGIN corresponds to your +own plugin name. + +The entry point of the plugin is defined via +#SND_PCM_PLUGIN_DEFINE_FUNC() macro. This macro defines the function +with a proper name to be referred from alsa-lib. The function takes +the following 6 arguments: +\code +int (snd_pcm_t **pcmp, const char *name, snd_config_t *root, + snd_config_t *conf, snd_pcm_stream_t stream, int mode) +\endcode +The first argument, pcmp, is the pointer to store the resultant PCM +handle. The arguments name, root, stream 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_pcm_extplug_create() or #snd_pcm_ioplug_create(), depending +on the plugin type. The PCM handle must be filled *pcmp in return. +Then this function must return either a value 0 when succeeded, or a +negative value as the error code. + +Finally, add #SND_PCM_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 myplug_info { + snd_pcm_extplug_t ext; + int my_own_data; + ... +}; + +SND_PCM_PLUGIN_DEFINE_FUNC(myplug) +{ + snd_config_iterator_t i, next; + struct myplug_info *myplug; + 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; + } + + myplug = calloc(1, sizeof(*myplug)); + if (myplug == NULL) + return -ENOMEM; + + myplug->ext.version = SND_PCM_EXTPLUG_VERSION; + myplug->ext.name = "My Own Plugin"; + myplug->ext.callback = &my_own_callback; + myplug->ext.private_data = myplug; + .... + + err = snd_pcm_extplug_create(&myplug->ext, name, stream, mode); + if (err < 0) { + myplug_free(myplug); + return err; + } + + *pcmp = myplug->ext.pcm; + return 0; +} + +SND_PCM_PLUGIN_SYMBOL(myplug); +\endcode + +Read the codes in alsa-plugins package for the real examples. + \section pcm_extplug External Plugin: Filter-Type Plugin @@ -443,6 +532,54 @@ and feeds to the output. Thus, this plugin always needs a slave PCM as its outp The plugin can modify the format and the channels of the input/output PCM. It can not modify the sample rate (because of simplicity reason). +The following fields have to be filled in extplug record before calling +#snd_pcm_extplug_create() : version, name, callback. +Otherfields are optional and should be initialized with zero. + +The constant #SND_PCM_EXTPLUG_VERSION must be passed to the version +field for the version check in alsa-lib. A non-NULL ASCII string +has to be passed to the name field. The callback field contains the +table of callback functions for this plugin (defined as +#snd_pcm_extplug_callback_t). + +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_pcm_extplug_create(). The pcm field +is the resultant PCM handle. The others are the current status of the +PCM. + +The callback functions in #snd_pcm_extplug_callback_t define the real +behavior of the driver. +At least, transfer callback must be given. This callback is called +at each time certain size of data block is transfered to the slave +PCM. Other callbacks 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. The hw_params and hw_free callbacks are called at +#snd_pcm_hw_params() and #snd_pcm_hw_free() API calls, +respectively. The last, dump callback, is called for printing the +information of the given plugin. + +The hw_params constraints can be defined via either +#snd_pcm_extplug_set_param_minmax() and #snd_pcm_extplug_set_param_list() +functions after calling #snd_pcm_extplug_create(). +The former defines the minimal and maximal acceptable values for the +given hw_params parameter (SND_PCM_EXTPLUG_HW_XXX). +This function can't be used for the format parameter. The latter +function specifies the available parameter values as the list. +As mentioned above, the rate can't be changed. Only changeable +parameters are sample format and channels. + +To define the constraints of the slave PCM configuration, use +either #snd_pcm_extplug_set_slave_param_minmax() and +#snd_pcm_extplug_set_slave_param_list(). The arguments are as same +as former functions. + +To clear the parameter constraints, call #snd_pcm_extplug_params_reset() +function. + */ /** @@ -460,8 +597,8 @@ It can not modify the sample rate (because of simplicity reason). * PCM plugin as "slave" config value. * name, root, stream and mode arguments are the values used for opening the PCM. * - * The callback is the mandatory field of extplug handle. At least, transfer callback - * must be set before calling this function. + * The callback is the mandatory field of extplug handle. At least, start, stop and + * pointer callbacks must be set before calling this function. */ int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name, snd_config_t *root, snd_config_t *slave_conf, @@ -505,7 +642,7 @@ int snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name, ext->plug.gen.slave = spcm; ext->plug.gen.close_slave = 1; - err = snd_pcm_new(&pcm, SND_PCM_TYPE_IOPLUG, name, stream, mode); + err = snd_pcm_new(&pcm, SND_PCM_TYPE_EXTPLUG, name, stream, mode); if (err < 0) { free(ext); return err; diff --git a/src/pcm/pcm_ioplug.c b/src/pcm/pcm_ioplug.c index 2dc97d24..6b9da111 100644 --- a/src/pcm/pcm_ioplug.c +++ b/src/pcm/pcm_ioplug.c @@ -757,13 +757,93 @@ static snd_pcm_fast_ops_t snd_pcm_ioplug_fast_ops = { * Exported functions */ -/*! \page pcm_external_plugins +/*! \page pcm_external_plugins PCM External Plugin SDK \section pcm_ioplug External Plugin: I/O Plugin The I/O-type plugin is a PCM plugin to work as the input or output terminal point, i.e. as a user-space PCM driver. +The new plugin is created via #snd_pcm_ioplug_create() function. +The first argument is a pointer of the pluging information. Some of +this struct must be initialized in prior to call +#snd_pcm_ioplug_create(). Then the function fills other fields in +return. The rest arguments, name, stream and mode, are usually +identical with the values passed from the ALSA plugin constructor. + +The following fields are mandatory: version, name, callback. +Otherfields are optional and should be initialized with zero. + +The constant #SND_PCM_IOPLUG_VERSION must be passed to the version +field for the version check in alsa-lib. A non-NULL ASCII string +has to be passed to the name field. The callback field contains the +table of callback functions for this plugin (defined as +#snd_pcm_ioplug_callback_t). + +flags field specifies the optional bit-flags. poll_fd and poll_events +specify the poll file descriptor and the corresponding poll events +(POLLIN, POLLOUT) for the plugin. If the plugin requires multiple +poll descriptors or poll descriptor(s) dynamically varying, set +poll_descriptors and poll_descriptors_count callbacks to the callback +table. Then the poll_fd and poll_events field are ignored. + +mmap_rw specifies whether the plugin behaves in the pseudo mmap mode. +When this value is set to 1, the plugin creates always a local buffer +and performs read/write calls using this buffer as if it's mmapped. +The address of local buffer can be obtained via +#snd_pcm_ioplug_mmap_areas() function. +When poll_fd, poll_events and mmap_rw fields are changed after +#snd_pcm_ioplug_create(), call #snd_pcm_ioplug_reinit_status() to +reflect the changes. + +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_pcm_ioplug_create(). The pcm field +is the resultant PCM handle. The others are the current status of the +PCM. + +The callback functions in #snd_pcm_ioplug_callback_t define the real +behavior of the driver. +At least, start, stop and pointer callbacks must be given. Other +callbacks are optional. The start and stop callbacks are called when +the PCM stream is started and stopped, repsectively. The pointer +callback returns the current DMA position, which may be called at any +time. + +The transfer callback is called when any data transfer happens. It +receives the area array, offset and the size to transfer. The area +array contains the array of snd_pcm_channel_area_t with the elements +of number of channels. + +When the PCM is closed, close callback is called. If the driver +allocates any internal buffers, they should be released in this +callback. The hw_params and hw_free callbacks are called when +hw_params are set and reset, respectively. Note that they may be +called multiple times according to the application. Similarly, +sw_params callback is called when sw_params is set or changed. + +The prepare, drain, pause and resume callbacks are called when +#snd_pcm_prepare(), #snd_pcm_drain(), #snd_pcm_pause(), and +#snd_pcm_resume() are called. The poll_descriptors_count and +poll_descriptors callbacks are used to return the multiple or dynamic +poll descriptors as mentioned above. The poll_revents callback is +used to modify poll events. If the driver needs to mangle the native +poll events to proper poll events for PCM, you can do it in this +callback. + +Finally, the dump callback is used to print the status of the plugin. + +The hw_params constraints can be defined via either +#snd_pcm_iplug_set_param_minmax() and #snd_pcm_ioplug_set_param_list() +functions after calling #snd_pcm_ioplug_create(). +The former defines the minimal and maximal acceptable values for the +given hw_params parameter (SND_PCM_IOPLUG_HW_XXX). +This function can't be used for the format parameter. The latter +function specifies the available parameter values as the list. + +To clear the parameter constraints, call #snd_pcm_ioplug_params_reset() function. + */ /** -- 2.47.1