1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_extplug.c 3d5ac70f0Sopenharmony_ci * \ingroup Plugin_SDK 4d5ac70f0Sopenharmony_ci * \brief External Filter Plugin SDK 5d5ac70f0Sopenharmony_ci * \author Takashi Iwai <tiwai@suse.de> 6d5ac70f0Sopenharmony_ci * \date 2005 7d5ac70f0Sopenharmony_ci */ 8d5ac70f0Sopenharmony_ci/* 9d5ac70f0Sopenharmony_ci * PCM - External Filter Plugin SDK 10d5ac70f0Sopenharmony_ci * Copyright (c) 2005 by Takashi Iwai <tiwai@suse.de> 11d5ac70f0Sopenharmony_ci * 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 14d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 15d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 16d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 17d5ac70f0Sopenharmony_ci * 18d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 19d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 20d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 22d5ac70f0Sopenharmony_ci * 23d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 24d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 25d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 26d5ac70f0Sopenharmony_ci * 27d5ac70f0Sopenharmony_ci */ 28d5ac70f0Sopenharmony_ci 29d5ac70f0Sopenharmony_ci#include "pcm_local.h" 30d5ac70f0Sopenharmony_ci#include "pcm_plugin.h" 31d5ac70f0Sopenharmony_ci#include "pcm_extplug.h" 32d5ac70f0Sopenharmony_ci#include "pcm_ext_parm.h" 33d5ac70f0Sopenharmony_ci 34d5ac70f0Sopenharmony_ci#ifndef PIC 35d5ac70f0Sopenharmony_ci/* entry for static linking */ 36d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_extplug = ""; 37d5ac70f0Sopenharmony_ci#endif 38d5ac70f0Sopenharmony_ci 39d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 40d5ac70f0Sopenharmony_ci 41d5ac70f0Sopenharmony_citypedef struct snd_pcm_extplug_priv { 42d5ac70f0Sopenharmony_ci snd_pcm_plugin_t plug; 43d5ac70f0Sopenharmony_ci snd_pcm_extplug_t *data; 44d5ac70f0Sopenharmony_ci struct snd_ext_parm params[SND_PCM_EXTPLUG_HW_PARAMS]; 45d5ac70f0Sopenharmony_ci struct snd_ext_parm sparams[SND_PCM_EXTPLUG_HW_PARAMS]; 46d5ac70f0Sopenharmony_ci} extplug_priv_t; 47d5ac70f0Sopenharmony_ci 48d5ac70f0Sopenharmony_cistatic const int hw_params_type[SND_PCM_EXTPLUG_HW_PARAMS] = { 49d5ac70f0Sopenharmony_ci [SND_PCM_EXTPLUG_HW_FORMAT] = SND_PCM_HW_PARAM_FORMAT, 50d5ac70f0Sopenharmony_ci [SND_PCM_EXTPLUG_HW_CHANNELS] = SND_PCM_HW_PARAM_CHANNELS 51d5ac70f0Sopenharmony_ci}; 52d5ac70f0Sopenharmony_ci 53d5ac70f0Sopenharmony_ci#define is_mask_type(i) (hw_params_type[i] < SND_PCM_HW_PARAM_FIRST_INTERVAL) 54d5ac70f0Sopenharmony_ci 55d5ac70f0Sopenharmony_cistatic const unsigned int excl_parbits[SND_PCM_EXTPLUG_HW_PARAMS] = { 56d5ac70f0Sopenharmony_ci [SND_PCM_EXTPLUG_HW_FORMAT] = (SND_PCM_HW_PARBIT_FORMAT| 57d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SUBFORMAT | 58d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SAMPLE_BITS), 59d5ac70f0Sopenharmony_ci [SND_PCM_EXTPLUG_HW_CHANNELS] = (SND_PCM_HW_PARBIT_CHANNELS| 60d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_FRAME_BITS), 61d5ac70f0Sopenharmony_ci}; 62d5ac70f0Sopenharmony_ci 63d5ac70f0Sopenharmony_ci/* 64d5ac70f0Sopenharmony_ci * set min/max values for the given parameter 65d5ac70f0Sopenharmony_ci */ 66d5ac70f0Sopenharmony_ciint snd_ext_parm_set_minmax(struct snd_ext_parm *parm, unsigned int min, unsigned int max) 67d5ac70f0Sopenharmony_ci{ 68d5ac70f0Sopenharmony_ci parm->num_list = 0; 69d5ac70f0Sopenharmony_ci free(parm->list); 70d5ac70f0Sopenharmony_ci parm->list = NULL; 71d5ac70f0Sopenharmony_ci parm->min = min; 72d5ac70f0Sopenharmony_ci parm->max = max; 73d5ac70f0Sopenharmony_ci parm->active = 1; 74d5ac70f0Sopenharmony_ci return 0; 75d5ac70f0Sopenharmony_ci} 76d5ac70f0Sopenharmony_ci 77d5ac70f0Sopenharmony_ci/* 78d5ac70f0Sopenharmony_ci * set the list of available values for the given parameter 79d5ac70f0Sopenharmony_ci */ 80d5ac70f0Sopenharmony_cistatic int val_compar(const void *ap, const void *bp) 81d5ac70f0Sopenharmony_ci{ 82d5ac70f0Sopenharmony_ci return *(const unsigned int *)ap - *(const unsigned int *)bp; 83d5ac70f0Sopenharmony_ci} 84d5ac70f0Sopenharmony_ci 85d5ac70f0Sopenharmony_ciint snd_ext_parm_set_list(struct snd_ext_parm *parm, unsigned int num_list, const unsigned int *list) 86d5ac70f0Sopenharmony_ci{ 87d5ac70f0Sopenharmony_ci unsigned int *new_list; 88d5ac70f0Sopenharmony_ci 89d5ac70f0Sopenharmony_ci new_list = malloc(sizeof(*new_list) * num_list); 90d5ac70f0Sopenharmony_ci if (new_list == NULL) 91d5ac70f0Sopenharmony_ci return -ENOMEM; 92d5ac70f0Sopenharmony_ci memcpy(new_list, list, sizeof(*new_list) * num_list); 93d5ac70f0Sopenharmony_ci qsort(new_list, num_list, sizeof(*new_list), val_compar); 94d5ac70f0Sopenharmony_ci 95d5ac70f0Sopenharmony_ci free(parm->list); 96d5ac70f0Sopenharmony_ci parm->num_list = num_list; 97d5ac70f0Sopenharmony_ci parm->list = new_list; 98d5ac70f0Sopenharmony_ci parm->active = 1; 99d5ac70f0Sopenharmony_ci return 0; 100d5ac70f0Sopenharmony_ci} 101d5ac70f0Sopenharmony_ci 102d5ac70f0Sopenharmony_civoid snd_ext_parm_clear(struct snd_ext_parm *parm) 103d5ac70f0Sopenharmony_ci{ 104d5ac70f0Sopenharmony_ci free(parm->list); 105d5ac70f0Sopenharmony_ci memset(parm, 0, sizeof(*parm)); 106d5ac70f0Sopenharmony_ci} 107d5ac70f0Sopenharmony_ci 108d5ac70f0Sopenharmony_ci/* 109d5ac70f0Sopenharmony_ci * limit the interval to the given list 110d5ac70f0Sopenharmony_ci */ 111d5ac70f0Sopenharmony_ciint snd_interval_list(snd_interval_t *ival, int num_list, unsigned int *list) 112d5ac70f0Sopenharmony_ci{ 113d5ac70f0Sopenharmony_ci int imin, imax; 114d5ac70f0Sopenharmony_ci int changed = 0; 115d5ac70f0Sopenharmony_ci 116d5ac70f0Sopenharmony_ci if (snd_interval_empty(ival)) 117d5ac70f0Sopenharmony_ci return -ENOENT; 118d5ac70f0Sopenharmony_ci for (imin = 0; imin < num_list; imin++) { 119d5ac70f0Sopenharmony_ci if (ival->min == list[imin] && ! ival->openmin) 120d5ac70f0Sopenharmony_ci break; 121d5ac70f0Sopenharmony_ci if (ival->min <= list[imin]) { 122d5ac70f0Sopenharmony_ci ival->min = list[imin]; 123d5ac70f0Sopenharmony_ci ival->openmin = 0; 124d5ac70f0Sopenharmony_ci changed = 1; 125d5ac70f0Sopenharmony_ci break; 126d5ac70f0Sopenharmony_ci } 127d5ac70f0Sopenharmony_ci } 128d5ac70f0Sopenharmony_ci if (imin >= num_list) 129d5ac70f0Sopenharmony_ci return -EINVAL; 130d5ac70f0Sopenharmony_ci for (imax = num_list - 1; imax >= imin; imax--) { 131d5ac70f0Sopenharmony_ci if (ival->max == list[imax] && ! ival->openmax) 132d5ac70f0Sopenharmony_ci break; 133d5ac70f0Sopenharmony_ci if (ival->max >= list[imax]) { 134d5ac70f0Sopenharmony_ci ival->max = list[imax]; 135d5ac70f0Sopenharmony_ci ival->openmax = 0; 136d5ac70f0Sopenharmony_ci changed = 1; 137d5ac70f0Sopenharmony_ci break; 138d5ac70f0Sopenharmony_ci } 139d5ac70f0Sopenharmony_ci } 140d5ac70f0Sopenharmony_ci if (imax < imin) 141d5ac70f0Sopenharmony_ci return -EINVAL; 142d5ac70f0Sopenharmony_ci return changed; 143d5ac70f0Sopenharmony_ci} 144d5ac70f0Sopenharmony_ci 145d5ac70f0Sopenharmony_ci/* 146d5ac70f0Sopenharmony_ci * refine the interval parameter 147d5ac70f0Sopenharmony_ci */ 148d5ac70f0Sopenharmony_ciint snd_ext_parm_interval_refine(snd_interval_t *ival, struct snd_ext_parm *parm, int type) 149d5ac70f0Sopenharmony_ci{ 150d5ac70f0Sopenharmony_ci parm += type; 151d5ac70f0Sopenharmony_ci if (! parm->active) 152d5ac70f0Sopenharmony_ci return 0; 153d5ac70f0Sopenharmony_ci ival->integer |= parm->integer; 154d5ac70f0Sopenharmony_ci if (parm->num_list) { 155d5ac70f0Sopenharmony_ci return snd_interval_list(ival, parm->num_list, parm->list); 156d5ac70f0Sopenharmony_ci } else if (parm->min || parm->max) { 157d5ac70f0Sopenharmony_ci snd_interval_t t; 158d5ac70f0Sopenharmony_ci memset(&t, 0, sizeof(t)); 159d5ac70f0Sopenharmony_ci snd_interval_set_minmax(&t, parm->min, parm->max); 160d5ac70f0Sopenharmony_ci t.integer = ival->integer; 161d5ac70f0Sopenharmony_ci return snd_interval_refine(ival, &t); 162d5ac70f0Sopenharmony_ci } 163d5ac70f0Sopenharmony_ci return 0; 164d5ac70f0Sopenharmony_ci} 165d5ac70f0Sopenharmony_ci 166d5ac70f0Sopenharmony_ci/* 167d5ac70f0Sopenharmony_ci * refine the mask parameter 168d5ac70f0Sopenharmony_ci */ 169d5ac70f0Sopenharmony_ciint snd_ext_parm_mask_refine(snd_mask_t *mask, struct snd_ext_parm *parm, int type) 170d5ac70f0Sopenharmony_ci{ 171d5ac70f0Sopenharmony_ci snd_mask_t bits; 172d5ac70f0Sopenharmony_ci unsigned int i; 173d5ac70f0Sopenharmony_ci 174d5ac70f0Sopenharmony_ci parm += type; 175d5ac70f0Sopenharmony_ci if (!parm->active) 176d5ac70f0Sopenharmony_ci return 0; 177d5ac70f0Sopenharmony_ci memset(&bits, 0, sizeof(bits)); 178d5ac70f0Sopenharmony_ci for (i = 0; i < parm->num_list; i++) 179d5ac70f0Sopenharmony_ci bits.bits[parm->list[i] / 32] |= 1U << (parm->list[i] % 32); 180d5ac70f0Sopenharmony_ci return snd_mask_refine(mask, &bits); 181d5ac70f0Sopenharmony_ci} 182d5ac70f0Sopenharmony_ci 183d5ac70f0Sopenharmony_ci 184d5ac70f0Sopenharmony_ci/* 185d5ac70f0Sopenharmony_ci * hw_refine callback 186d5ac70f0Sopenharmony_ci */ 187d5ac70f0Sopenharmony_cistatic int extplug_hw_refine(snd_pcm_hw_params_t *hw_params, 188d5ac70f0Sopenharmony_ci struct snd_ext_parm *parm) 189d5ac70f0Sopenharmony_ci{ 190d5ac70f0Sopenharmony_ci int i, err, change = 0; 191d5ac70f0Sopenharmony_ci for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { 192d5ac70f0Sopenharmony_ci int type = hw_params_type[i]; 193d5ac70f0Sopenharmony_ci if (is_mask_type(i)) 194d5ac70f0Sopenharmony_ci err = snd_ext_parm_mask_refine(hw_param_mask(hw_params, type), 195d5ac70f0Sopenharmony_ci parm, i); 196d5ac70f0Sopenharmony_ci else 197d5ac70f0Sopenharmony_ci err = snd_ext_parm_interval_refine(hw_param_interval(hw_params, type), 198d5ac70f0Sopenharmony_ci parm, i); 199d5ac70f0Sopenharmony_ci if (err < 0) 200d5ac70f0Sopenharmony_ci return err; 201d5ac70f0Sopenharmony_ci change |= err; 202d5ac70f0Sopenharmony_ci } 203d5ac70f0Sopenharmony_ci return change; 204d5ac70f0Sopenharmony_ci} 205d5ac70f0Sopenharmony_ci 206d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_hw_refine_cprepare(snd_pcm_t *pcm, 207d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params) 208d5ac70f0Sopenharmony_ci{ 209d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 210d5ac70f0Sopenharmony_ci int err; 211d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t access_mask = { SND_PCM_ACCBIT_SHM }; 212d5ac70f0Sopenharmony_ci err = _snd_pcm_hw_param_set_mask(params, SND_PCM_HW_PARAM_ACCESS, 213d5ac70f0Sopenharmony_ci &access_mask); 214d5ac70f0Sopenharmony_ci if (err < 0) 215d5ac70f0Sopenharmony_ci return err; 216d5ac70f0Sopenharmony_ci err = extplug_hw_refine(params, ext->params); 217d5ac70f0Sopenharmony_ci if (err < 0) 218d5ac70f0Sopenharmony_ci return err; 219d5ac70f0Sopenharmony_ci params->info &= ~(SND_PCM_INFO_MMAP | SND_PCM_INFO_MMAP_VALID); 220d5ac70f0Sopenharmony_ci return 0; 221d5ac70f0Sopenharmony_ci} 222d5ac70f0Sopenharmony_ci 223d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_hw_refine_sprepare(snd_pcm_t *pcm, 224d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 225d5ac70f0Sopenharmony_ci{ 226d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 227d5ac70f0Sopenharmony_ci snd_pcm_access_mask_t saccess_mask = { SND_PCM_ACCBIT_MMAP }; 228d5ac70f0Sopenharmony_ci _snd_pcm_hw_params_any(sparams); 229d5ac70f0Sopenharmony_ci _snd_pcm_hw_param_set_mask(sparams, SND_PCM_HW_PARAM_ACCESS, 230d5ac70f0Sopenharmony_ci &saccess_mask); 231d5ac70f0Sopenharmony_ci extplug_hw_refine(sparams, ext->sparams); 232d5ac70f0Sopenharmony_ci return 0; 233d5ac70f0Sopenharmony_ci} 234d5ac70f0Sopenharmony_ci 235d5ac70f0Sopenharmony_cistatic unsigned int get_links(struct snd_ext_parm *params) 236d5ac70f0Sopenharmony_ci{ 237d5ac70f0Sopenharmony_ci int i; 238d5ac70f0Sopenharmony_ci unsigned int links = (SND_PCM_HW_PARBIT_FORMAT | 239d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SUBFORMAT | 240d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_SAMPLE_BITS | 241d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_CHANNELS | 242d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_FRAME_BITS | 243d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_RATE | 244d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIODS | 245d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_SIZE | 246d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_PERIOD_TIME | 247d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_SIZE | 248d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_BUFFER_TIME | 249d5ac70f0Sopenharmony_ci SND_PCM_HW_PARBIT_TICK_TIME); 250d5ac70f0Sopenharmony_ci 251d5ac70f0Sopenharmony_ci for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { 252d5ac70f0Sopenharmony_ci if (params[i].active && !params[i].keep_link) 253d5ac70f0Sopenharmony_ci links &= ~excl_parbits[i]; 254d5ac70f0Sopenharmony_ci } 255d5ac70f0Sopenharmony_ci return links; 256d5ac70f0Sopenharmony_ci} 257d5ac70f0Sopenharmony_ci 258d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_hw_refine_schange(snd_pcm_t *pcm, 259d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 260d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 261d5ac70f0Sopenharmony_ci{ 262d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 263d5ac70f0Sopenharmony_ci unsigned int links = get_links(ext->sparams); 264d5ac70f0Sopenharmony_ci 265d5ac70f0Sopenharmony_ci return _snd_pcm_hw_params_refine(sparams, links, params); 266d5ac70f0Sopenharmony_ci} 267d5ac70f0Sopenharmony_ci 268d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_hw_refine_cchange(snd_pcm_t *pcm, 269d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *params, 270d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *sparams) 271d5ac70f0Sopenharmony_ci{ 272d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 273d5ac70f0Sopenharmony_ci unsigned int links = get_links(ext->params); 274d5ac70f0Sopenharmony_ci 275d5ac70f0Sopenharmony_ci return _snd_pcm_hw_params_refine(params, links, sparams); 276d5ac70f0Sopenharmony_ci} 277d5ac70f0Sopenharmony_ci 278d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 279d5ac70f0Sopenharmony_ci{ 280d5ac70f0Sopenharmony_ci int err = snd_pcm_hw_refine_slave(pcm, params, 281d5ac70f0Sopenharmony_ci snd_pcm_extplug_hw_refine_cprepare, 282d5ac70f0Sopenharmony_ci snd_pcm_extplug_hw_refine_cchange, 283d5ac70f0Sopenharmony_ci snd_pcm_extplug_hw_refine_sprepare, 284d5ac70f0Sopenharmony_ci snd_pcm_extplug_hw_refine_schange, 285d5ac70f0Sopenharmony_ci snd_pcm_generic_hw_refine); 286d5ac70f0Sopenharmony_ci return err; 287d5ac70f0Sopenharmony_ci} 288d5ac70f0Sopenharmony_ci 289d5ac70f0Sopenharmony_ci/* 290d5ac70f0Sopenharmony_ci * hw_params callback 291d5ac70f0Sopenharmony_ci */ 292d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 293d5ac70f0Sopenharmony_ci{ 294d5ac70f0Sopenharmony_ci 295d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 296d5ac70f0Sopenharmony_ci snd_pcm_t *slave = ext->plug.gen.slave; 297d5ac70f0Sopenharmony_ci int err = snd_pcm_hw_params_slave(pcm, params, 298d5ac70f0Sopenharmony_ci snd_pcm_extplug_hw_refine_cchange, 299d5ac70f0Sopenharmony_ci snd_pcm_extplug_hw_refine_sprepare, 300d5ac70f0Sopenharmony_ci snd_pcm_extplug_hw_refine_schange, 301d5ac70f0Sopenharmony_ci snd_pcm_generic_hw_params); 302d5ac70f0Sopenharmony_ci if (err < 0) 303d5ac70f0Sopenharmony_ci return err; 304d5ac70f0Sopenharmony_ci ext->data->slave_format = slave->format; 305d5ac70f0Sopenharmony_ci ext->data->slave_subformat = slave->subformat; 306d5ac70f0Sopenharmony_ci ext->data->slave_channels = slave->channels; 307d5ac70f0Sopenharmony_ci ext->data->rate = slave->rate; 308d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_format)(params, &ext->data->format); 309d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_subformat)(params, &ext->data->subformat); 310d5ac70f0Sopenharmony_ci INTERNAL(snd_pcm_hw_params_get_channels)(params, &ext->data->channels); 311d5ac70f0Sopenharmony_ci 312d5ac70f0Sopenharmony_ci if (ext->data->callback->hw_params) { 313d5ac70f0Sopenharmony_ci err = ext->data->callback->hw_params(ext->data, params); 314d5ac70f0Sopenharmony_ci if (err < 0) 315d5ac70f0Sopenharmony_ci return err; 316d5ac70f0Sopenharmony_ci } 317d5ac70f0Sopenharmony_ci return 0; 318d5ac70f0Sopenharmony_ci} 319d5ac70f0Sopenharmony_ci 320d5ac70f0Sopenharmony_ci/* 321d5ac70f0Sopenharmony_ci * hw_free callback 322d5ac70f0Sopenharmony_ci */ 323d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_hw_free(snd_pcm_t *pcm) 324d5ac70f0Sopenharmony_ci{ 325d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 326d5ac70f0Sopenharmony_ci 327d5ac70f0Sopenharmony_ci snd_pcm_hw_free(ext->plug.gen.slave); 328d5ac70f0Sopenharmony_ci if (ext->data->callback->hw_free) 329d5ac70f0Sopenharmony_ci return ext->data->callback->hw_free(ext->data); 330d5ac70f0Sopenharmony_ci return 0; 331d5ac70f0Sopenharmony_ci} 332d5ac70f0Sopenharmony_ci 333d5ac70f0Sopenharmony_ci/* 334d5ac70f0Sopenharmony_ci * write_areas skeleton - call transfer callback 335d5ac70f0Sopenharmony_ci */ 336d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t 337d5ac70f0Sopenharmony_cisnd_pcm_extplug_write_areas(snd_pcm_t *pcm, 338d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 339d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 340d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size, 341d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas, 342d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset, 343d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *slave_sizep) 344d5ac70f0Sopenharmony_ci{ 345d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 346d5ac70f0Sopenharmony_ci 347d5ac70f0Sopenharmony_ci if (size > *slave_sizep) 348d5ac70f0Sopenharmony_ci size = *slave_sizep; 349d5ac70f0Sopenharmony_ci size = ext->data->callback->transfer(ext->data, slave_areas, slave_offset, 350d5ac70f0Sopenharmony_ci areas, offset, size); 351d5ac70f0Sopenharmony_ci *slave_sizep = size; 352d5ac70f0Sopenharmony_ci return size; 353d5ac70f0Sopenharmony_ci} 354d5ac70f0Sopenharmony_ci 355d5ac70f0Sopenharmony_ci/* 356d5ac70f0Sopenharmony_ci * read_areas skeleton - call transfer callback 357d5ac70f0Sopenharmony_ci */ 358d5ac70f0Sopenharmony_cistatic snd_pcm_uframes_t 359d5ac70f0Sopenharmony_cisnd_pcm_extplug_read_areas(snd_pcm_t *pcm, 360d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *areas, 361d5ac70f0Sopenharmony_ci snd_pcm_uframes_t offset, 362d5ac70f0Sopenharmony_ci snd_pcm_uframes_t size, 363d5ac70f0Sopenharmony_ci const snd_pcm_channel_area_t *slave_areas, 364d5ac70f0Sopenharmony_ci snd_pcm_uframes_t slave_offset, 365d5ac70f0Sopenharmony_ci snd_pcm_uframes_t *slave_sizep) 366d5ac70f0Sopenharmony_ci{ 367d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 368d5ac70f0Sopenharmony_ci 369d5ac70f0Sopenharmony_ci if (size > *slave_sizep) 370d5ac70f0Sopenharmony_ci size = *slave_sizep; 371d5ac70f0Sopenharmony_ci size = ext->data->callback->transfer(ext->data, areas, offset, 372d5ac70f0Sopenharmony_ci slave_areas, slave_offset, size); 373d5ac70f0Sopenharmony_ci *slave_sizep = size; 374d5ac70f0Sopenharmony_ci return size; 375d5ac70f0Sopenharmony_ci} 376d5ac70f0Sopenharmony_ci 377d5ac70f0Sopenharmony_ci/* 378d5ac70f0Sopenharmony_ci * call init callback 379d5ac70f0Sopenharmony_ci */ 380d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_init(snd_pcm_t *pcm) 381d5ac70f0Sopenharmony_ci{ 382d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 383d5ac70f0Sopenharmony_ci return ext->data->callback->init(ext->data); 384d5ac70f0Sopenharmony_ci} 385d5ac70f0Sopenharmony_ci 386d5ac70f0Sopenharmony_ci/* 387d5ac70f0Sopenharmony_ci * dump setup 388d5ac70f0Sopenharmony_ci */ 389d5ac70f0Sopenharmony_cistatic void snd_pcm_extplug_dump(snd_pcm_t *pcm, snd_output_t *out) 390d5ac70f0Sopenharmony_ci{ 391d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 392d5ac70f0Sopenharmony_ci 393d5ac70f0Sopenharmony_ci if (ext->data->callback->dump) 394d5ac70f0Sopenharmony_ci ext->data->callback->dump(ext->data, out); 395d5ac70f0Sopenharmony_ci else { 396d5ac70f0Sopenharmony_ci if (ext->data->name) 397d5ac70f0Sopenharmony_ci snd_output_printf(out, "%s\n", ext->data->name); 398d5ac70f0Sopenharmony_ci else 399d5ac70f0Sopenharmony_ci snd_output_printf(out, "External PCM Plugin\n"); 400d5ac70f0Sopenharmony_ci if (pcm->setup) { 401d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 402d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 403d5ac70f0Sopenharmony_ci } 404d5ac70f0Sopenharmony_ci } 405d5ac70f0Sopenharmony_ci snd_output_printf(out, "Slave: "); 406d5ac70f0Sopenharmony_ci snd_pcm_dump(ext->plug.gen.slave, out); 407d5ac70f0Sopenharmony_ci} 408d5ac70f0Sopenharmony_ci 409d5ac70f0Sopenharmony_cistatic void clear_ext_params(extplug_priv_t *ext) 410d5ac70f0Sopenharmony_ci{ 411d5ac70f0Sopenharmony_ci int i; 412d5ac70f0Sopenharmony_ci for (i = 0; i < SND_PCM_EXTPLUG_HW_PARAMS; i++) { 413d5ac70f0Sopenharmony_ci snd_ext_parm_clear(&ext->params[i]); 414d5ac70f0Sopenharmony_ci snd_ext_parm_clear(&ext->sparams[i]); 415d5ac70f0Sopenharmony_ci } 416d5ac70f0Sopenharmony_ci} 417d5ac70f0Sopenharmony_ci 418d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_close(snd_pcm_t *pcm) 419d5ac70f0Sopenharmony_ci{ 420d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 421d5ac70f0Sopenharmony_ci 422d5ac70f0Sopenharmony_ci snd_pcm_close(ext->plug.gen.slave); 423d5ac70f0Sopenharmony_ci clear_ext_params(ext); 424d5ac70f0Sopenharmony_ci if (ext->data->callback->close) 425d5ac70f0Sopenharmony_ci ext->data->callback->close(ext->data); 426d5ac70f0Sopenharmony_ci free(ext); 427d5ac70f0Sopenharmony_ci return 0; 428d5ac70f0Sopenharmony_ci} 429d5ac70f0Sopenharmony_ci 430d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_query_t **snd_pcm_extplug_query_chmaps(snd_pcm_t *pcm) 431d5ac70f0Sopenharmony_ci{ 432d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 433d5ac70f0Sopenharmony_ci 434d5ac70f0Sopenharmony_ci if (ext->data->version >= 0x010002 && 435d5ac70f0Sopenharmony_ci ext->data->callback->query_chmaps) 436d5ac70f0Sopenharmony_ci return ext->data->callback->query_chmaps(ext->data); 437d5ac70f0Sopenharmony_ci return snd_pcm_generic_query_chmaps(pcm); 438d5ac70f0Sopenharmony_ci} 439d5ac70f0Sopenharmony_ci 440d5ac70f0Sopenharmony_cistatic snd_pcm_chmap_t *snd_pcm_extplug_get_chmap(snd_pcm_t *pcm) 441d5ac70f0Sopenharmony_ci{ 442d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 443d5ac70f0Sopenharmony_ci 444d5ac70f0Sopenharmony_ci if (ext->data->version >= 0x010002 && 445d5ac70f0Sopenharmony_ci ext->data->callback->get_chmap) 446d5ac70f0Sopenharmony_ci return ext->data->callback->get_chmap(ext->data); 447d5ac70f0Sopenharmony_ci return snd_pcm_generic_get_chmap(pcm); 448d5ac70f0Sopenharmony_ci} 449d5ac70f0Sopenharmony_ci 450d5ac70f0Sopenharmony_cistatic int snd_pcm_extplug_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) 451d5ac70f0Sopenharmony_ci{ 452d5ac70f0Sopenharmony_ci extplug_priv_t *ext = pcm->private_data; 453d5ac70f0Sopenharmony_ci 454d5ac70f0Sopenharmony_ci if (ext->data->version >= 0x010002 && 455d5ac70f0Sopenharmony_ci ext->data->callback->set_chmap) 456d5ac70f0Sopenharmony_ci return ext->data->callback->set_chmap(ext->data, map); 457d5ac70f0Sopenharmony_ci return snd_pcm_generic_set_chmap(pcm, map); 458d5ac70f0Sopenharmony_ci} 459d5ac70f0Sopenharmony_ci 460d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_extplug_ops = { 461d5ac70f0Sopenharmony_ci .close = snd_pcm_extplug_close, 462d5ac70f0Sopenharmony_ci .info = snd_pcm_generic_info, 463d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_extplug_hw_refine, 464d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_extplug_hw_params, 465d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_extplug_hw_free, 466d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_generic_sw_params, 467d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_generic_channel_info, 468d5ac70f0Sopenharmony_ci .dump = snd_pcm_extplug_dump, 469d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_generic_nonblock, 470d5ac70f0Sopenharmony_ci .async = snd_pcm_generic_async, 471d5ac70f0Sopenharmony_ci .mmap = snd_pcm_generic_mmap, 472d5ac70f0Sopenharmony_ci .munmap = snd_pcm_generic_munmap, 473d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_extplug_query_chmaps, 474d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_extplug_get_chmap, 475d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_extplug_set_chmap, 476d5ac70f0Sopenharmony_ci}; 477d5ac70f0Sopenharmony_ci 478d5ac70f0Sopenharmony_ci#endif /* !DOC_HIDDEN */ 479d5ac70f0Sopenharmony_ci 480d5ac70f0Sopenharmony_ci/* 481d5ac70f0Sopenharmony_ci * Exported functions 482d5ac70f0Sopenharmony_ci */ 483d5ac70f0Sopenharmony_ci 484d5ac70f0Sopenharmony_ci/*! \page pcm_external_plugins PCM External Plugin SDK 485d5ac70f0Sopenharmony_ci 486d5ac70f0Sopenharmony_ci\section pcm_externals External Plugins 487d5ac70f0Sopenharmony_ci 488d5ac70f0Sopenharmony_ciThe external plugins are implemented in a shared object file located 489d5ac70f0Sopenharmony_ciat /usr/lib/alsa-lib (the exact location depends on the build option 490d5ac70f0Sopenharmony_ciand asoundrc configuration). It has to be the file like 491d5ac70f0Sopenharmony_cilibasound_module_pcm_MYPLUGIN.so, where MYPLUGIN corresponds to your 492d5ac70f0Sopenharmony_ciown plugin name. 493d5ac70f0Sopenharmony_ci 494d5ac70f0Sopenharmony_ciThe entry point of the plugin is defined via 495d5ac70f0Sopenharmony_ci#SND_PCM_PLUGIN_DEFINE_FUNC() macro. This macro defines the function 496d5ac70f0Sopenharmony_ciwith a proper name to be referred from alsa-lib. The function takes 497d5ac70f0Sopenharmony_cithe following 6 arguments: 498d5ac70f0Sopenharmony_ci\code 499d5ac70f0Sopenharmony_ciint (snd_pcm_t **pcmp, const char *name, snd_config_t *root, 500d5ac70f0Sopenharmony_ci snd_config_t *conf, snd_pcm_stream_t stream, int mode) 501d5ac70f0Sopenharmony_ci\endcode 502d5ac70f0Sopenharmony_ciThe first argument, pcmp, is the pointer to store the resultant PCM 503d5ac70f0Sopenharmony_cihandle. The arguments name, root, stream and mode are the parameters 504d5ac70f0Sopenharmony_cito be passed to the plugin constructor. The conf is the configuration 505d5ac70f0Sopenharmony_citree for the plugin. The arguments above are defined in the macro 506d5ac70f0Sopenharmony_ciitself, so don't use variables with the same names to shadow 507d5ac70f0Sopenharmony_ciparameters. 508d5ac70f0Sopenharmony_ci 509d5ac70f0Sopenharmony_ciAfter parsing the configuration parameters in the given conf tree, 510d5ac70f0Sopenharmony_ciusually you will call the external plugin API function, 511d5ac70f0Sopenharmony_ci#snd_pcm_extplug_create() or #snd_pcm_ioplug_create(), depending 512d5ac70f0Sopenharmony_cion the plugin type. The PCM handle must be filled *pcmp in return. 513d5ac70f0Sopenharmony_ciThen this function must return either a value 0 when succeeded, or a 514d5ac70f0Sopenharmony_cinegative value as the error code. 515d5ac70f0Sopenharmony_ci 516d5ac70f0Sopenharmony_ciFinally, add #SND_PCM_PLUGIN_SYMBOL() with the name of your 517d5ac70f0Sopenharmony_ciplugin as the argument at the end. This defines the proper versioned 518d5ac70f0Sopenharmony_cisymbol as the reference. 519d5ac70f0Sopenharmony_ci 520d5ac70f0Sopenharmony_ciThe typical code would look like below: 521d5ac70f0Sopenharmony_ci\code 522d5ac70f0Sopenharmony_cistruct myplug_info { 523d5ac70f0Sopenharmony_ci snd_pcm_extplug_t ext; 524d5ac70f0Sopenharmony_ci int my_own_data; 525d5ac70f0Sopenharmony_ci ... 526d5ac70f0Sopenharmony_ci}; 527d5ac70f0Sopenharmony_ci 528d5ac70f0Sopenharmony_ciSND_PCM_PLUGIN_DEFINE_FUNC(myplug) 529d5ac70f0Sopenharmony_ci{ 530d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 531d5ac70f0Sopenharmony_ci snd_config_t *slave = NULL; 532d5ac70f0Sopenharmony_ci struct myplug_info *myplug; 533d5ac70f0Sopenharmony_ci int err; 534d5ac70f0Sopenharmony_ci 535d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 536d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 537d5ac70f0Sopenharmony_ci const char *id; 538d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 539d5ac70f0Sopenharmony_ci continue; 540d5ac70f0Sopenharmony_ci if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0) 541d5ac70f0Sopenharmony_ci continue; 542d5ac70f0Sopenharmony_ci if (strcmp(id, "slave") == 0) { 543d5ac70f0Sopenharmony_ci slave = n; 544d5ac70f0Sopenharmony_ci continue; 545d5ac70f0Sopenharmony_ci } 546d5ac70f0Sopenharmony_ci if (strcmp(id, "my_own_parameter") == 0) { 547d5ac70f0Sopenharmony_ci .... 548d5ac70f0Sopenharmony_ci continue; 549d5ac70f0Sopenharmony_ci } 550d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 551d5ac70f0Sopenharmony_ci return -EINVAL; 552d5ac70f0Sopenharmony_ci } 553d5ac70f0Sopenharmony_ci 554d5ac70f0Sopenharmony_ci if (! slave) { 555d5ac70f0Sopenharmony_ci SNDERR("No slave defined for myplug"); 556d5ac70f0Sopenharmony_ci return -EINVAL; 557d5ac70f0Sopenharmony_ci } 558d5ac70f0Sopenharmony_ci 559d5ac70f0Sopenharmony_ci myplug = calloc(1, sizeof(*myplug)); 560d5ac70f0Sopenharmony_ci if (myplug == NULL) 561d5ac70f0Sopenharmony_ci return -ENOMEM; 562d5ac70f0Sopenharmony_ci 563d5ac70f0Sopenharmony_ci myplug->ext.version = SND_PCM_EXTPLUG_VERSION; 564d5ac70f0Sopenharmony_ci myplug->ext.name = "My Own Plugin"; 565d5ac70f0Sopenharmony_ci myplug->ext.callback = &my_own_callback; 566d5ac70f0Sopenharmony_ci myplug->ext.private_data = myplug; 567d5ac70f0Sopenharmony_ci .... 568d5ac70f0Sopenharmony_ci 569d5ac70f0Sopenharmony_ci err = snd_pcm_extplug_create(&myplug->ext, name, root, conf, stream, mode); 570d5ac70f0Sopenharmony_ci if (err < 0) { 571d5ac70f0Sopenharmony_ci myplug_free(myplug); 572d5ac70f0Sopenharmony_ci return err; 573d5ac70f0Sopenharmony_ci } 574d5ac70f0Sopenharmony_ci 575d5ac70f0Sopenharmony_ci *pcmp = myplug->ext.pcm; 576d5ac70f0Sopenharmony_ci return 0; 577d5ac70f0Sopenharmony_ci} 578d5ac70f0Sopenharmony_ci 579d5ac70f0Sopenharmony_ciSND_PCM_PLUGIN_SYMBOL(myplug); 580d5ac70f0Sopenharmony_ci\endcode 581d5ac70f0Sopenharmony_ci 582d5ac70f0Sopenharmony_ciRead the codes in alsa-plugins package for the real examples. 583d5ac70f0Sopenharmony_ci 584d5ac70f0Sopenharmony_ci 585d5ac70f0Sopenharmony_ci\section pcm_extplug External Plugin: Filter-Type Plugin 586d5ac70f0Sopenharmony_ci 587d5ac70f0Sopenharmony_ciThe filter-type plugin is a plugin to convert the PCM signals from the input 588d5ac70f0Sopenharmony_ciand feeds to the output. Thus, this plugin always needs a slave PCM as its output. 589d5ac70f0Sopenharmony_ci 590d5ac70f0Sopenharmony_ciThe plugin can modify the format and the channels of the input/output PCM. 591d5ac70f0Sopenharmony_ciIt can <i>not</i> modify the sample rate (because of simplicity reason). 592d5ac70f0Sopenharmony_ci 593d5ac70f0Sopenharmony_ciThe following fields have to be filled in extplug record before calling 594d5ac70f0Sopenharmony_ci#snd_pcm_extplug_create() : version, name, callback. 595d5ac70f0Sopenharmony_ciOtherfields are optional and should be initialized with zero. 596d5ac70f0Sopenharmony_ci 597d5ac70f0Sopenharmony_ciThe constant #SND_PCM_EXTPLUG_VERSION must be passed to the version 598d5ac70f0Sopenharmony_cifield for the version check in alsa-lib. A non-NULL ASCII string 599d5ac70f0Sopenharmony_cihas to be passed to the name field. The callback field contains the 600d5ac70f0Sopenharmony_citable of callback functions for this plugin (defined as 601d5ac70f0Sopenharmony_ci#snd_pcm_extplug_callback_t). 602d5ac70f0Sopenharmony_ci 603d5ac70f0Sopenharmony_ciThe driver can set an arbitrary value (pointer) to private_data 604d5ac70f0Sopenharmony_cifield to refer its own data in the callbacks. 605d5ac70f0Sopenharmony_ci 606d5ac70f0Sopenharmony_ciThe rest fields are filled by #snd_pcm_extplug_create(). The pcm field 607d5ac70f0Sopenharmony_ciis the resultant PCM handle. The others are the current status of the 608d5ac70f0Sopenharmony_ciPCM. 609d5ac70f0Sopenharmony_ci 610d5ac70f0Sopenharmony_ciThe callback functions in #snd_pcm_extplug_callback_t define the real 611d5ac70f0Sopenharmony_cibehavior of the driver. 612d5ac70f0Sopenharmony_ciAt least, transfer callback must be given. This callback is called 613d5ac70f0Sopenharmony_ciat each time certain size of data block is transfered to the slave 614d5ac70f0Sopenharmony_ciPCM. Other callbacks are optional. 615d5ac70f0Sopenharmony_ci 616d5ac70f0Sopenharmony_ciThe close callback is called when the PCM is closed. If the plugin 617d5ac70f0Sopenharmony_ciallocates private resources, this is the place to release them 618d5ac70f0Sopenharmony_ciagain. The hw_params and hw_free callbacks are called at 619d5ac70f0Sopenharmony_ci#snd_pcm_hw_params() and #snd_pcm_hw_free() API calls, 620d5ac70f0Sopenharmony_cirespectively. The last, dump callback, is called for printing the 621d5ac70f0Sopenharmony_ciinformation of the given plugin. 622d5ac70f0Sopenharmony_ci 623d5ac70f0Sopenharmony_ciThe init callback is called when the PCM is at prepare state or any 624d5ac70f0Sopenharmony_ciinitialization is issued. Use this callback to reset the PCM instance 625d5ac70f0Sopenharmony_cito a sane initial state. 626d5ac70f0Sopenharmony_ci 627d5ac70f0Sopenharmony_ciThe hw_params constraints can be defined via either 628d5ac70f0Sopenharmony_ci#snd_pcm_extplug_set_param_minmax() and #snd_pcm_extplug_set_param_list() 629d5ac70f0Sopenharmony_cifunctions after calling #snd_pcm_extplug_create(). 630d5ac70f0Sopenharmony_ciThe former defines the minimal and maximal acceptable values for the 631d5ac70f0Sopenharmony_cigiven hw_params parameter (SND_PCM_EXTPLUG_HW_XXX). 632d5ac70f0Sopenharmony_ciThis function can't be used for the format parameter. The latter 633d5ac70f0Sopenharmony_cifunction specifies the available parameter values as the list. 634d5ac70f0Sopenharmony_ciAs mentioned above, the rate can't be changed. Only changeable 635d5ac70f0Sopenharmony_ciparameters are sample format and channels. 636d5ac70f0Sopenharmony_ci 637d5ac70f0Sopenharmony_ciTo define the constraints of the slave PCM configuration, use 638d5ac70f0Sopenharmony_cieither #snd_pcm_extplug_set_slave_param_minmax() and 639d5ac70f0Sopenharmony_ci#snd_pcm_extplug_set_slave_param_list(). The arguments are as same 640d5ac70f0Sopenharmony_cias former functions. 641d5ac70f0Sopenharmony_ci 642d5ac70f0Sopenharmony_ciTo clear the parameter constraints, call #snd_pcm_extplug_params_reset() 643d5ac70f0Sopenharmony_cifunction. 644d5ac70f0Sopenharmony_ci 645d5ac70f0Sopenharmony_ciWhen using snd_pcm_extplug_set_param_*() or snd_pcm_extplug_set_slave_param_*() 646d5ac70f0Sopenharmony_cifor any parameter. This parameter is no longer linked between the client and 647d5ac70f0Sopenharmony_cislave PCM. Therefore it could differ and the extplug has to support conversion 648d5ac70f0Sopenharmony_cibetween all valid parameter configurations. To keep the client and slave 649d5ac70f0Sopenharmony_ciparameter linked #snd_pcm_extplug_set_param_link() can be used for the 650d5ac70f0Sopenharmony_cicorresponding parameter. For example if the extplug does not support channel nor 651d5ac70f0Sopenharmony_ciformat conversion the supported client parameters can be limited with 652d5ac70f0Sopenharmony_cisnd_pcm_extplug_set_param_*() and afterwards 653d5ac70f0Sopenharmony_cisnd_pcm_extplug_set_param_link(ext, SND_PCM_EXTPLUG_HW_FORMAT, 1) and 654d5ac70f0Sopenharmony_cisnd_pcm_extplug_set_param_link(ext, SND_PCM_EXTPLUG_HW_CHANNELS, 1) should be 655d5ac70f0Sopenharmony_cicalled to keep the client and slave parameters the same. 656d5ac70f0Sopenharmony_ci*/ 657d5ac70f0Sopenharmony_ci 658d5ac70f0Sopenharmony_ci/** 659d5ac70f0Sopenharmony_ci * \brief Create an extplug instance 660d5ac70f0Sopenharmony_ci * \param extplug the extplug handle 661d5ac70f0Sopenharmony_ci * \param name name of the PCM 662d5ac70f0Sopenharmony_ci * \param root configuration tree root 663d5ac70f0Sopenharmony_ci * \param slave_conf slave configuration root 664d5ac70f0Sopenharmony_ci * \param stream stream direction 665d5ac70f0Sopenharmony_ci * \param mode PCM open mode 666d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 667d5ac70f0Sopenharmony_ci * 668d5ac70f0Sopenharmony_ci * Creates the extplug instance based on the given handle. 669d5ac70f0Sopenharmony_ci * The slave_conf argument is mandatory, and usually taken from the config tree of the 670d5ac70f0Sopenharmony_ci * PCM plugin as "slave" config value. 671d5ac70f0Sopenharmony_ci * name, root, stream and mode arguments are the values used for opening the PCM. 672d5ac70f0Sopenharmony_ci * 673d5ac70f0Sopenharmony_ci * The callback is the mandatory field of extplug handle. At least, start, stop and 674d5ac70f0Sopenharmony_ci * pointer callbacks must be set before calling this function. 675d5ac70f0Sopenharmony_ci */ 676d5ac70f0Sopenharmony_ciint snd_pcm_extplug_create(snd_pcm_extplug_t *extplug, const char *name, 677d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *slave_conf, 678d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 679d5ac70f0Sopenharmony_ci{ 680d5ac70f0Sopenharmony_ci extplug_priv_t *ext; 681d5ac70f0Sopenharmony_ci int err; 682d5ac70f0Sopenharmony_ci snd_pcm_t *spcm, *pcm; 683d5ac70f0Sopenharmony_ci snd_config_t *sconf; 684d5ac70f0Sopenharmony_ci 685d5ac70f0Sopenharmony_ci assert(root); 686d5ac70f0Sopenharmony_ci assert(extplug && extplug->callback); 687d5ac70f0Sopenharmony_ci assert(extplug->callback->transfer); 688d5ac70f0Sopenharmony_ci assert(slave_conf); 689d5ac70f0Sopenharmony_ci 690d5ac70f0Sopenharmony_ci /* We support 1.0.0 to current */ 691d5ac70f0Sopenharmony_ci if (extplug->version < 0x010000 || 692d5ac70f0Sopenharmony_ci extplug->version > SND_PCM_EXTPLUG_VERSION) { 693d5ac70f0Sopenharmony_ci SNDERR("extplug: Plugin version mismatch: 0x%x", 694d5ac70f0Sopenharmony_ci extplug->version); 695d5ac70f0Sopenharmony_ci return -ENXIO; 696d5ac70f0Sopenharmony_ci } 697d5ac70f0Sopenharmony_ci 698d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, slave_conf, &sconf, 0); 699d5ac70f0Sopenharmony_ci if (err < 0) 700d5ac70f0Sopenharmony_ci return err; 701d5ac70f0Sopenharmony_ci err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, NULL); 702d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 703d5ac70f0Sopenharmony_ci if (err < 0) 704d5ac70f0Sopenharmony_ci return err; 705d5ac70f0Sopenharmony_ci 706d5ac70f0Sopenharmony_ci ext = calloc(1, sizeof(*ext)); 707d5ac70f0Sopenharmony_ci if (! ext) 708d5ac70f0Sopenharmony_ci return -ENOMEM; 709d5ac70f0Sopenharmony_ci 710d5ac70f0Sopenharmony_ci ext->data = extplug; 711d5ac70f0Sopenharmony_ci extplug->stream = stream; 712d5ac70f0Sopenharmony_ci 713d5ac70f0Sopenharmony_ci snd_pcm_plugin_init(&ext->plug); 714d5ac70f0Sopenharmony_ci ext->plug.read = snd_pcm_extplug_read_areas; 715d5ac70f0Sopenharmony_ci ext->plug.write = snd_pcm_extplug_write_areas; 716d5ac70f0Sopenharmony_ci ext->plug.undo_read = snd_pcm_plugin_undo_read_generic; 717d5ac70f0Sopenharmony_ci ext->plug.undo_write = snd_pcm_plugin_undo_write_generic; 718d5ac70f0Sopenharmony_ci ext->plug.gen.slave = spcm; 719d5ac70f0Sopenharmony_ci ext->plug.gen.close_slave = 1; 720d5ac70f0Sopenharmony_ci if (extplug->version >= 0x010001 && extplug->callback->init) 721d5ac70f0Sopenharmony_ci ext->plug.init = snd_pcm_extplug_init; 722d5ac70f0Sopenharmony_ci 723d5ac70f0Sopenharmony_ci err = snd_pcm_new(&pcm, SND_PCM_TYPE_EXTPLUG, name, stream, mode); 724d5ac70f0Sopenharmony_ci if (err < 0) { 725d5ac70f0Sopenharmony_ci free(ext); 726d5ac70f0Sopenharmony_ci return err; 727d5ac70f0Sopenharmony_ci } 728d5ac70f0Sopenharmony_ci 729d5ac70f0Sopenharmony_ci extplug->pcm = pcm; 730d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_extplug_ops; 731d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_plugin_fast_ops; 732d5ac70f0Sopenharmony_ci pcm->private_data = ext; 733d5ac70f0Sopenharmony_ci pcm->poll_fd = spcm->poll_fd; 734d5ac70f0Sopenharmony_ci pcm->poll_events = spcm->poll_events; 735d5ac70f0Sopenharmony_ci pcm->tstamp_type = spcm->tstamp_type; 736d5ac70f0Sopenharmony_ci snd_pcm_set_hw_ptr(pcm, &ext->plug.hw_ptr, -1, 0); 737d5ac70f0Sopenharmony_ci snd_pcm_set_appl_ptr(pcm, &ext->plug.appl_ptr, -1, 0); 738d5ac70f0Sopenharmony_ci 739d5ac70f0Sopenharmony_ci return 0; 740d5ac70f0Sopenharmony_ci} 741d5ac70f0Sopenharmony_ci 742d5ac70f0Sopenharmony_ci/** 743d5ac70f0Sopenharmony_ci * \brief Delete the extplug instance 744d5ac70f0Sopenharmony_ci * \param extplug the extplug handle to delete 745d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 746d5ac70f0Sopenharmony_ci * 747d5ac70f0Sopenharmony_ci * The destructor of extplug instance. 748d5ac70f0Sopenharmony_ci * Closes the PCM and deletes the associated resources. 749d5ac70f0Sopenharmony_ci */ 750d5ac70f0Sopenharmony_ciint snd_pcm_extplug_delete(snd_pcm_extplug_t *extplug) 751d5ac70f0Sopenharmony_ci{ 752d5ac70f0Sopenharmony_ci return snd_pcm_close(extplug->pcm); 753d5ac70f0Sopenharmony_ci} 754d5ac70f0Sopenharmony_ci 755d5ac70f0Sopenharmony_ci 756d5ac70f0Sopenharmony_ci/** 757d5ac70f0Sopenharmony_ci * \brief Reset extplug parameters 758d5ac70f0Sopenharmony_ci * \param extplug the extplug handle 759d5ac70f0Sopenharmony_ci * 760d5ac70f0Sopenharmony_ci * Resets the all parameters for the given extplug handle. 761d5ac70f0Sopenharmony_ci */ 762d5ac70f0Sopenharmony_civoid snd_pcm_extplug_params_reset(snd_pcm_extplug_t *extplug) 763d5ac70f0Sopenharmony_ci{ 764d5ac70f0Sopenharmony_ci extplug_priv_t *ext = extplug->pcm->private_data; 765d5ac70f0Sopenharmony_ci clear_ext_params(ext); 766d5ac70f0Sopenharmony_ci} 767d5ac70f0Sopenharmony_ci 768d5ac70f0Sopenharmony_ci/** 769d5ac70f0Sopenharmony_ci * \brief Set slave parameter as the list 770d5ac70f0Sopenharmony_ci * \param extplug the extplug handle 771d5ac70f0Sopenharmony_ci * \param type parameter type 772d5ac70f0Sopenharmony_ci * \param num_list number of available values 773d5ac70f0Sopenharmony_ci * \param list the list of available values 774d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 775d5ac70f0Sopenharmony_ci * 776d5ac70f0Sopenharmony_ci * Sets the slave parameter as the list. 777d5ac70f0Sopenharmony_ci * The available values of the given parameter type of the slave PCM is restricted 778d5ac70f0Sopenharmony_ci * to the ones of the given list. 779d5ac70f0Sopenharmony_ci */ 780d5ac70f0Sopenharmony_ciint snd_pcm_extplug_set_slave_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list) 781d5ac70f0Sopenharmony_ci{ 782d5ac70f0Sopenharmony_ci extplug_priv_t *ext = extplug->pcm->private_data; 783d5ac70f0Sopenharmony_ci if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) { 784d5ac70f0Sopenharmony_ci SNDERR("EXTPLUG: invalid parameter type %d", type); 785d5ac70f0Sopenharmony_ci return -EINVAL; 786d5ac70f0Sopenharmony_ci } 787d5ac70f0Sopenharmony_ci return snd_ext_parm_set_list(&ext->sparams[type], num_list, list); 788d5ac70f0Sopenharmony_ci} 789d5ac70f0Sopenharmony_ci 790d5ac70f0Sopenharmony_ci/** 791d5ac70f0Sopenharmony_ci * \brief Set slave parameter as the min/max values 792d5ac70f0Sopenharmony_ci * \param extplug the extplug handle 793d5ac70f0Sopenharmony_ci * \param type parameter type 794d5ac70f0Sopenharmony_ci * \param min the minimum value 795d5ac70f0Sopenharmony_ci * \param max the maximum value 796d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 797d5ac70f0Sopenharmony_ci * 798d5ac70f0Sopenharmony_ci * Sets the slave parameter as the min/max values. 799d5ac70f0Sopenharmony_ci * The available values of the given parameter type of the slave PCM is restricted 800d5ac70f0Sopenharmony_ci * between the given minimum and maximum values. 801d5ac70f0Sopenharmony_ci */ 802d5ac70f0Sopenharmony_ciint snd_pcm_extplug_set_slave_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max) 803d5ac70f0Sopenharmony_ci{ 804d5ac70f0Sopenharmony_ci extplug_priv_t *ext = extplug->pcm->private_data; 805d5ac70f0Sopenharmony_ci if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) { 806d5ac70f0Sopenharmony_ci SNDERR("EXTPLUG: invalid parameter type %d", type); 807d5ac70f0Sopenharmony_ci return -EINVAL; 808d5ac70f0Sopenharmony_ci } 809d5ac70f0Sopenharmony_ci if (is_mask_type(type)) { 810d5ac70f0Sopenharmony_ci SNDERR("EXTPLUG: invalid parameter type %d", type); 811d5ac70f0Sopenharmony_ci return -EINVAL; 812d5ac70f0Sopenharmony_ci } 813d5ac70f0Sopenharmony_ci return snd_ext_parm_set_minmax(&ext->sparams[type], min, max); 814d5ac70f0Sopenharmony_ci} 815d5ac70f0Sopenharmony_ci 816d5ac70f0Sopenharmony_ci/** 817d5ac70f0Sopenharmony_ci * \brief Set master parameter as the list 818d5ac70f0Sopenharmony_ci * \param extplug the extplug handle 819d5ac70f0Sopenharmony_ci * \param type parameter type 820d5ac70f0Sopenharmony_ci * \param num_list number of available values 821d5ac70f0Sopenharmony_ci * \param list the list of available values 822d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 823d5ac70f0Sopenharmony_ci * 824d5ac70f0Sopenharmony_ci * Sets the master parameter as the list. 825d5ac70f0Sopenharmony_ci * The available values of the given parameter type of this PCM (as input) is restricted 826d5ac70f0Sopenharmony_ci * to the ones of the given list. 827d5ac70f0Sopenharmony_ci */ 828d5ac70f0Sopenharmony_ciint snd_pcm_extplug_set_param_list(snd_pcm_extplug_t *extplug, int type, unsigned int num_list, const unsigned int *list) 829d5ac70f0Sopenharmony_ci{ 830d5ac70f0Sopenharmony_ci extplug_priv_t *ext = extplug->pcm->private_data; 831d5ac70f0Sopenharmony_ci if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) { 832d5ac70f0Sopenharmony_ci SNDERR("EXTPLUG: invalid parameter type %d", type); 833d5ac70f0Sopenharmony_ci return -EINVAL; 834d5ac70f0Sopenharmony_ci } 835d5ac70f0Sopenharmony_ci return snd_ext_parm_set_list(&ext->params[type], num_list, list); 836d5ac70f0Sopenharmony_ci} 837d5ac70f0Sopenharmony_ci 838d5ac70f0Sopenharmony_ci/** 839d5ac70f0Sopenharmony_ci * \brief Set master parameter as the min/max values 840d5ac70f0Sopenharmony_ci * \param extplug the extplug handle 841d5ac70f0Sopenharmony_ci * \param type parameter type 842d5ac70f0Sopenharmony_ci * \param min the minimum value 843d5ac70f0Sopenharmony_ci * \param max the maximum value 844d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code 845d5ac70f0Sopenharmony_ci * 846d5ac70f0Sopenharmony_ci * Sets the master parameter as the min/max values. 847d5ac70f0Sopenharmony_ci * The available values of the given parameter type of this PCM (as input) is restricted 848d5ac70f0Sopenharmony_ci * between the given minimum and maximum values. 849d5ac70f0Sopenharmony_ci */ 850d5ac70f0Sopenharmony_ciint snd_pcm_extplug_set_param_minmax(snd_pcm_extplug_t *extplug, int type, unsigned int min, unsigned int max) 851d5ac70f0Sopenharmony_ci{ 852d5ac70f0Sopenharmony_ci extplug_priv_t *ext = extplug->pcm->private_data; 853d5ac70f0Sopenharmony_ci if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) { 854d5ac70f0Sopenharmony_ci SNDERR("EXTPLUG: invalid parameter type %d", type); 855d5ac70f0Sopenharmony_ci return -EINVAL; 856d5ac70f0Sopenharmony_ci } 857d5ac70f0Sopenharmony_ci if (is_mask_type(type)) { 858d5ac70f0Sopenharmony_ci SNDERR("EXTPLUG: invalid parameter type %d", type); 859d5ac70f0Sopenharmony_ci return -EINVAL; 860d5ac70f0Sopenharmony_ci } 861d5ac70f0Sopenharmony_ci return snd_ext_parm_set_minmax(&ext->params[type], min, max); 862d5ac70f0Sopenharmony_ci} 863d5ac70f0Sopenharmony_ci 864d5ac70f0Sopenharmony_ci/** 865d5ac70f0Sopenharmony_ci * @brief Keep the client and slave format/channels the same if requested. This 866d5ac70f0Sopenharmony_ci * is for example useful if this extplug does not support any channel 867d5ac70f0Sopenharmony_ci * conversion. 868d5ac70f0Sopenharmony_ci * @param extplug the extplug handle 869d5ac70f0Sopenharmony_ci * @param type parameter type 870d5ac70f0Sopenharmony_ci * @param keep_link if 1 the parameter identified by type will be kept the same 871d5ac70f0Sopenharmony_ci * for the client and slave PCM of this extplug 872d5ac70f0Sopenharmony_ci * @return 0 if successful, or a negative error code 873d5ac70f0Sopenharmony_ci */ 874d5ac70f0Sopenharmony_ciint snd_pcm_extplug_set_param_link(snd_pcm_extplug_t *extplug, int type, 875d5ac70f0Sopenharmony_ci int keep_link) 876d5ac70f0Sopenharmony_ci{ 877d5ac70f0Sopenharmony_ci extplug_priv_t *ext = extplug->pcm->private_data; 878d5ac70f0Sopenharmony_ci 879d5ac70f0Sopenharmony_ci if (type < 0 || type >= SND_PCM_EXTPLUG_HW_PARAMS) { 880d5ac70f0Sopenharmony_ci SNDERR("EXTPLUG: invalid parameter type %d", type); 881d5ac70f0Sopenharmony_ci return -EINVAL; 882d5ac70f0Sopenharmony_ci } 883d5ac70f0Sopenharmony_ci ext->params[type].keep_link = keep_link ? 1 : 0; 884d5ac70f0Sopenharmony_ci ext->sparams[type].keep_link = keep_link ? 1 : 0; 885d5ac70f0Sopenharmony_ci return 0; 886d5ac70f0Sopenharmony_ci} 887