1d5ac70f0Sopenharmony_ci/** 2d5ac70f0Sopenharmony_ci * \file pcm/pcm_hooks.c 3d5ac70f0Sopenharmony_ci * \ingroup PCM_Hook 4d5ac70f0Sopenharmony_ci * \brief PCM Hook Interface 5d5ac70f0Sopenharmony_ci * \author Abramo Bagnara <abramo@alsa-project.org> 6d5ac70f0Sopenharmony_ci * \author Jaroslav Kysela <perex@perex.cz> 7d5ac70f0Sopenharmony_ci * \date 2000-2001 8d5ac70f0Sopenharmony_ci */ 9d5ac70f0Sopenharmony_ci/* 10d5ac70f0Sopenharmony_ci * PCM - Hook functions 11d5ac70f0Sopenharmony_ci * Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org> 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * 14d5ac70f0Sopenharmony_ci * This library is free software; you can redistribute it and/or modify 15d5ac70f0Sopenharmony_ci * it under the terms of the GNU Lesser General Public License as 16d5ac70f0Sopenharmony_ci * published by the Free Software Foundation; either version 2.1 of 17d5ac70f0Sopenharmony_ci * the License, or (at your option) any later version. 18d5ac70f0Sopenharmony_ci * 19d5ac70f0Sopenharmony_ci * This program is distributed in the hope that it will be useful, 20d5ac70f0Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 21d5ac70f0Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22d5ac70f0Sopenharmony_ci * GNU Lesser General Public License for more details. 23d5ac70f0Sopenharmony_ci * 24d5ac70f0Sopenharmony_ci * You should have received a copy of the GNU Lesser General Public 25d5ac70f0Sopenharmony_ci * License along with this library; if not, write to the Free Software 26d5ac70f0Sopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 27d5ac70f0Sopenharmony_ci * 28d5ac70f0Sopenharmony_ci */ 29d5ac70f0Sopenharmony_ci 30d5ac70f0Sopenharmony_ci#include "pcm_local.h" 31d5ac70f0Sopenharmony_ci#include "pcm_generic.h" 32d5ac70f0Sopenharmony_ci 33d5ac70f0Sopenharmony_ci#ifndef PIC 34d5ac70f0Sopenharmony_ci/* entry for static linking */ 35d5ac70f0Sopenharmony_ciconst char *_snd_module_pcm_hooks = ""; 36d5ac70f0Sopenharmony_ci#endif 37d5ac70f0Sopenharmony_ci 38d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 39d5ac70f0Sopenharmony_cistruct _snd_pcm_hook { 40d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 41d5ac70f0Sopenharmony_ci snd_pcm_hook_func_t func; 42d5ac70f0Sopenharmony_ci void *private_data; 43d5ac70f0Sopenharmony_ci struct list_head list; 44d5ac70f0Sopenharmony_ci}; 45d5ac70f0Sopenharmony_ci 46d5ac70f0Sopenharmony_cistruct snd_pcm_hook_dllist { 47d5ac70f0Sopenharmony_ci void *dlobj; 48d5ac70f0Sopenharmony_ci struct list_head list; 49d5ac70f0Sopenharmony_ci}; 50d5ac70f0Sopenharmony_ci 51d5ac70f0Sopenharmony_citypedef struct { 52d5ac70f0Sopenharmony_ci snd_pcm_generic_t gen; 53d5ac70f0Sopenharmony_ci struct list_head hooks[SND_PCM_HOOK_TYPE_LAST + 1]; 54d5ac70f0Sopenharmony_ci struct list_head dllist; 55d5ac70f0Sopenharmony_ci} snd_pcm_hooks_t; 56d5ac70f0Sopenharmony_ci#endif 57d5ac70f0Sopenharmony_ci 58d5ac70f0Sopenharmony_cistatic int hook_add_dlobj(snd_pcm_t *pcm, void *dlobj) 59d5ac70f0Sopenharmony_ci{ 60d5ac70f0Sopenharmony_ci snd_pcm_hooks_t *h = pcm->private_data; 61d5ac70f0Sopenharmony_ci struct snd_pcm_hook_dllist *dl; 62d5ac70f0Sopenharmony_ci 63d5ac70f0Sopenharmony_ci dl = malloc(sizeof(*dl)); 64d5ac70f0Sopenharmony_ci if (!dl) 65d5ac70f0Sopenharmony_ci return -ENOMEM; 66d5ac70f0Sopenharmony_ci 67d5ac70f0Sopenharmony_ci dl->dlobj = dlobj; 68d5ac70f0Sopenharmony_ci list_add_tail(&dl->list, &h->dllist); 69d5ac70f0Sopenharmony_ci return 0; 70d5ac70f0Sopenharmony_ci} 71d5ac70f0Sopenharmony_ci 72d5ac70f0Sopenharmony_cistatic void hook_remove_dlobj(struct snd_pcm_hook_dllist *dl) 73d5ac70f0Sopenharmony_ci{ 74d5ac70f0Sopenharmony_ci list_del(&dl->list); 75d5ac70f0Sopenharmony_ci snd_dlclose(dl->dlobj); 76d5ac70f0Sopenharmony_ci free(dl); 77d5ac70f0Sopenharmony_ci} 78d5ac70f0Sopenharmony_ci 79d5ac70f0Sopenharmony_cistatic int snd_pcm_hooks_close(snd_pcm_t *pcm) 80d5ac70f0Sopenharmony_ci{ 81d5ac70f0Sopenharmony_ci snd_pcm_hooks_t *h = pcm->private_data; 82d5ac70f0Sopenharmony_ci struct list_head *pos, *next; 83d5ac70f0Sopenharmony_ci unsigned int k; 84d5ac70f0Sopenharmony_ci int res = 0, err; 85d5ac70f0Sopenharmony_ci 86d5ac70f0Sopenharmony_ci list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_CLOSE]) { 87d5ac70f0Sopenharmony_ci snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); 88d5ac70f0Sopenharmony_ci err = hook->func(hook); 89d5ac70f0Sopenharmony_ci if (err < 0) 90d5ac70f0Sopenharmony_ci res = err; 91d5ac70f0Sopenharmony_ci } 92d5ac70f0Sopenharmony_ci for (k = 0; k <= SND_PCM_HOOK_TYPE_LAST; ++k) { 93d5ac70f0Sopenharmony_ci struct list_head *hooks = &h->hooks[k]; 94d5ac70f0Sopenharmony_ci while (!list_empty(hooks)) { 95d5ac70f0Sopenharmony_ci snd_pcm_hook_t *hook; 96d5ac70f0Sopenharmony_ci pos = hooks->next; 97d5ac70f0Sopenharmony_ci hook = list_entry(pos, snd_pcm_hook_t, list); 98d5ac70f0Sopenharmony_ci snd_pcm_hook_remove(hook); 99d5ac70f0Sopenharmony_ci } 100d5ac70f0Sopenharmony_ci } 101d5ac70f0Sopenharmony_ci while (!list_empty(&h->dllist)) { 102d5ac70f0Sopenharmony_ci pos = h->dllist.next; 103d5ac70f0Sopenharmony_ci hook_remove_dlobj(list_entry(pos, struct snd_pcm_hook_dllist, list)); 104d5ac70f0Sopenharmony_ci } 105d5ac70f0Sopenharmony_ci err = snd_pcm_generic_close(pcm); 106d5ac70f0Sopenharmony_ci if (err < 0) 107d5ac70f0Sopenharmony_ci res = err; 108d5ac70f0Sopenharmony_ci return res; 109d5ac70f0Sopenharmony_ci} 110d5ac70f0Sopenharmony_ci 111d5ac70f0Sopenharmony_cistatic int snd_pcm_hooks_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) 112d5ac70f0Sopenharmony_ci{ 113d5ac70f0Sopenharmony_ci snd_pcm_hooks_t *h = pcm->private_data; 114d5ac70f0Sopenharmony_ci struct list_head *pos, *next; 115d5ac70f0Sopenharmony_ci int err = snd_pcm_generic_hw_params(pcm, params); 116d5ac70f0Sopenharmony_ci if (err < 0) 117d5ac70f0Sopenharmony_ci return err; 118d5ac70f0Sopenharmony_ci list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_HW_PARAMS]) { 119d5ac70f0Sopenharmony_ci snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); 120d5ac70f0Sopenharmony_ci err = hook->func(hook); 121d5ac70f0Sopenharmony_ci if (err < 0) 122d5ac70f0Sopenharmony_ci return err; 123d5ac70f0Sopenharmony_ci } 124d5ac70f0Sopenharmony_ci return 0; 125d5ac70f0Sopenharmony_ci} 126d5ac70f0Sopenharmony_ci 127d5ac70f0Sopenharmony_cistatic int snd_pcm_hooks_hw_free(snd_pcm_t *pcm) 128d5ac70f0Sopenharmony_ci{ 129d5ac70f0Sopenharmony_ci snd_pcm_hooks_t *h = pcm->private_data; 130d5ac70f0Sopenharmony_ci struct list_head *pos, *next; 131d5ac70f0Sopenharmony_ci int err = snd_pcm_generic_hw_free(pcm); 132d5ac70f0Sopenharmony_ci if (err < 0) 133d5ac70f0Sopenharmony_ci return err; 134d5ac70f0Sopenharmony_ci list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_HW_FREE]) { 135d5ac70f0Sopenharmony_ci snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list); 136d5ac70f0Sopenharmony_ci err = hook->func(hook); 137d5ac70f0Sopenharmony_ci if (err < 0) 138d5ac70f0Sopenharmony_ci return err; 139d5ac70f0Sopenharmony_ci } 140d5ac70f0Sopenharmony_ci return 0; 141d5ac70f0Sopenharmony_ci} 142d5ac70f0Sopenharmony_ci 143d5ac70f0Sopenharmony_cistatic void snd_pcm_hooks_dump(snd_pcm_t *pcm, snd_output_t *out) 144d5ac70f0Sopenharmony_ci{ 145d5ac70f0Sopenharmony_ci snd_pcm_hooks_t *h = pcm->private_data; 146d5ac70f0Sopenharmony_ci snd_output_printf(out, "Hooks PCM\n"); 147d5ac70f0Sopenharmony_ci if (pcm->setup) { 148d5ac70f0Sopenharmony_ci snd_output_printf(out, "Its setup is:\n"); 149d5ac70f0Sopenharmony_ci snd_pcm_dump_setup(pcm, out); 150d5ac70f0Sopenharmony_ci } 151d5ac70f0Sopenharmony_ci snd_output_printf(out, "Slave: "); 152d5ac70f0Sopenharmony_ci snd_pcm_dump(h->gen.slave, out); 153d5ac70f0Sopenharmony_ci} 154d5ac70f0Sopenharmony_ci 155d5ac70f0Sopenharmony_cistatic const snd_pcm_ops_t snd_pcm_hooks_ops = { 156d5ac70f0Sopenharmony_ci .close = snd_pcm_hooks_close, 157d5ac70f0Sopenharmony_ci .info = snd_pcm_generic_info, 158d5ac70f0Sopenharmony_ci .hw_refine = snd_pcm_generic_hw_refine, 159d5ac70f0Sopenharmony_ci .hw_params = snd_pcm_hooks_hw_params, 160d5ac70f0Sopenharmony_ci .hw_free = snd_pcm_hooks_hw_free, 161d5ac70f0Sopenharmony_ci .sw_params = snd_pcm_generic_sw_params, 162d5ac70f0Sopenharmony_ci .channel_info = snd_pcm_generic_channel_info, 163d5ac70f0Sopenharmony_ci .dump = snd_pcm_hooks_dump, 164d5ac70f0Sopenharmony_ci .nonblock = snd_pcm_generic_nonblock, 165d5ac70f0Sopenharmony_ci .async = snd_pcm_generic_async, 166d5ac70f0Sopenharmony_ci .mmap = snd_pcm_generic_mmap, 167d5ac70f0Sopenharmony_ci .munmap = snd_pcm_generic_munmap, 168d5ac70f0Sopenharmony_ci .query_chmaps = snd_pcm_generic_query_chmaps, 169d5ac70f0Sopenharmony_ci .get_chmap = snd_pcm_generic_get_chmap, 170d5ac70f0Sopenharmony_ci .set_chmap = snd_pcm_generic_set_chmap, 171d5ac70f0Sopenharmony_ci}; 172d5ac70f0Sopenharmony_ci 173d5ac70f0Sopenharmony_cistatic const snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = { 174d5ac70f0Sopenharmony_ci .status = snd_pcm_generic_status, 175d5ac70f0Sopenharmony_ci .state = snd_pcm_generic_state, 176d5ac70f0Sopenharmony_ci .hwsync = snd_pcm_generic_hwsync, 177d5ac70f0Sopenharmony_ci .delay = snd_pcm_generic_delay, 178d5ac70f0Sopenharmony_ci .prepare = snd_pcm_generic_prepare, 179d5ac70f0Sopenharmony_ci .reset = snd_pcm_generic_reset, 180d5ac70f0Sopenharmony_ci .start = snd_pcm_generic_start, 181d5ac70f0Sopenharmony_ci .drop = snd_pcm_generic_drop, 182d5ac70f0Sopenharmony_ci .drain = snd_pcm_generic_drain, 183d5ac70f0Sopenharmony_ci .pause = snd_pcm_generic_pause, 184d5ac70f0Sopenharmony_ci .rewindable = snd_pcm_generic_rewindable, 185d5ac70f0Sopenharmony_ci .rewind = snd_pcm_generic_rewind, 186d5ac70f0Sopenharmony_ci .forwardable = snd_pcm_generic_forwardable, 187d5ac70f0Sopenharmony_ci .forward = snd_pcm_generic_forward, 188d5ac70f0Sopenharmony_ci .resume = snd_pcm_generic_resume, 189d5ac70f0Sopenharmony_ci .link = snd_pcm_generic_link, 190d5ac70f0Sopenharmony_ci .link_slaves = snd_pcm_generic_link_slaves, 191d5ac70f0Sopenharmony_ci .unlink = snd_pcm_generic_unlink, 192d5ac70f0Sopenharmony_ci .writei = snd_pcm_generic_writei, 193d5ac70f0Sopenharmony_ci .writen = snd_pcm_generic_writen, 194d5ac70f0Sopenharmony_ci .readi = snd_pcm_generic_readi, 195d5ac70f0Sopenharmony_ci .readn = snd_pcm_generic_readn, 196d5ac70f0Sopenharmony_ci .avail_update = snd_pcm_generic_avail_update, 197d5ac70f0Sopenharmony_ci .mmap_commit = snd_pcm_generic_mmap_commit, 198d5ac70f0Sopenharmony_ci .htimestamp = snd_pcm_generic_htimestamp, 199d5ac70f0Sopenharmony_ci .poll_descriptors_count = snd_pcm_generic_poll_descriptors_count, 200d5ac70f0Sopenharmony_ci .poll_descriptors = snd_pcm_generic_poll_descriptors, 201d5ac70f0Sopenharmony_ci .poll_revents = snd_pcm_generic_poll_revents, 202d5ac70f0Sopenharmony_ci .may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min, 203d5ac70f0Sopenharmony_ci}; 204d5ac70f0Sopenharmony_ci 205d5ac70f0Sopenharmony_ci/** 206d5ac70f0Sopenharmony_ci * \brief Creates a new hooks PCM 207d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 208d5ac70f0Sopenharmony_ci * \param name Name of PCM 209d5ac70f0Sopenharmony_ci * \param slave Slave PCM 210d5ac70f0Sopenharmony_ci * \param close_slave If set, slave PCM handle is closed when hooks PCM is closed 211d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 212d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 213d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 214d5ac70f0Sopenharmony_ci * changed in future. 215d5ac70f0Sopenharmony_ci */ 216d5ac70f0Sopenharmony_ciint snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int close_slave) 217d5ac70f0Sopenharmony_ci{ 218d5ac70f0Sopenharmony_ci snd_pcm_t *pcm; 219d5ac70f0Sopenharmony_ci snd_pcm_hooks_t *h; 220d5ac70f0Sopenharmony_ci unsigned int k; 221d5ac70f0Sopenharmony_ci int err; 222d5ac70f0Sopenharmony_ci assert(pcmp && slave); 223d5ac70f0Sopenharmony_ci h = calloc(1, sizeof(snd_pcm_hooks_t)); 224d5ac70f0Sopenharmony_ci if (!h) 225d5ac70f0Sopenharmony_ci return -ENOMEM; 226d5ac70f0Sopenharmony_ci h->gen.slave = slave; 227d5ac70f0Sopenharmony_ci h->gen.close_slave = close_slave; 228d5ac70f0Sopenharmony_ci for (k = 0; k <= SND_PCM_HOOK_TYPE_LAST; ++k) { 229d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&h->hooks[k]); 230d5ac70f0Sopenharmony_ci } 231d5ac70f0Sopenharmony_ci INIT_LIST_HEAD(&h->dllist); 232d5ac70f0Sopenharmony_ci err = snd_pcm_new(&pcm, SND_PCM_TYPE_HOOKS, name, slave->stream, slave->mode); 233d5ac70f0Sopenharmony_ci if (err < 0) { 234d5ac70f0Sopenharmony_ci free(h); 235d5ac70f0Sopenharmony_ci return err; 236d5ac70f0Sopenharmony_ci } 237d5ac70f0Sopenharmony_ci pcm->ops = &snd_pcm_hooks_ops; 238d5ac70f0Sopenharmony_ci pcm->fast_ops = &snd_pcm_hooks_fast_ops; 239d5ac70f0Sopenharmony_ci pcm->private_data = h; 240d5ac70f0Sopenharmony_ci pcm->poll_fd = slave->poll_fd; 241d5ac70f0Sopenharmony_ci pcm->poll_events = slave->poll_events; 242d5ac70f0Sopenharmony_ci pcm->mmap_shadow = 1; 243d5ac70f0Sopenharmony_ci pcm->tstamp_type = slave->tstamp_type; 244d5ac70f0Sopenharmony_ci snd_pcm_link_hw_ptr(pcm, slave); 245d5ac70f0Sopenharmony_ci snd_pcm_link_appl_ptr(pcm, slave); 246d5ac70f0Sopenharmony_ci *pcmp = pcm; 247d5ac70f0Sopenharmony_ci 248d5ac70f0Sopenharmony_ci return 0; 249d5ac70f0Sopenharmony_ci} 250d5ac70f0Sopenharmony_ci 251d5ac70f0Sopenharmony_ci/*! \page pcm_plugins 252d5ac70f0Sopenharmony_ci 253d5ac70f0Sopenharmony_ci\section pcm_plugins_hooks Plugin: hooks 254d5ac70f0Sopenharmony_ci 255d5ac70f0Sopenharmony_ciThis plugin is used to call some 'hook' function when this plugin is opened, 256d5ac70f0Sopenharmony_cimodified or closed. 257d5ac70f0Sopenharmony_ciTypically, it is used to change control values for a certain state 258d5ac70f0Sopenharmony_cispecially for the PCM (see the example below). 259d5ac70f0Sopenharmony_ci 260d5ac70f0Sopenharmony_ci\code 261d5ac70f0Sopenharmony_ci# Hook arguments definition 262d5ac70f0Sopenharmony_cihook_args.NAME { 263d5ac70f0Sopenharmony_ci ... # Arbitrary arguments 264d5ac70f0Sopenharmony_ci} 265d5ac70f0Sopenharmony_ci 266d5ac70f0Sopenharmony_ci# PCM hook type 267d5ac70f0Sopenharmony_cipcm_hook_type.NAME { 268d5ac70f0Sopenharmony_ci [lib STR] # Library file (default libasound.so) 269d5ac70f0Sopenharmony_ci [install STR] # Install function (default _snd_pcm_hook_NAME_install) 270d5ac70f0Sopenharmony_ci} 271d5ac70f0Sopenharmony_ci 272d5ac70f0Sopenharmony_ci# PCM hook definition 273d5ac70f0Sopenharmony_cipcm_hook.NAME { 274d5ac70f0Sopenharmony_ci type STR # PCM Hook type (see pcm_hook_type) 275d5ac70f0Sopenharmony_ci [args STR] # Arguments for install function (see hook_args) 276d5ac70f0Sopenharmony_ci # or 277d5ac70f0Sopenharmony_ci [args { }] # Arguments for install function 278d5ac70f0Sopenharmony_ci} 279d5ac70f0Sopenharmony_ci 280d5ac70f0Sopenharmony_ci# PCM hook plugin 281d5ac70f0Sopenharmony_cipcm.NAME { 282d5ac70f0Sopenharmony_ci type hooks # PCM with hooks 283d5ac70f0Sopenharmony_ci slave STR # Slave name 284d5ac70f0Sopenharmony_ci # or 285d5ac70f0Sopenharmony_ci slave { # Slave definition 286d5ac70f0Sopenharmony_ci pcm STR # Slave PCM name 287d5ac70f0Sopenharmony_ci # or 288d5ac70f0Sopenharmony_ci pcm { } # Slave PCM definition 289d5ac70f0Sopenharmony_ci } 290d5ac70f0Sopenharmony_ci hooks { 291d5ac70f0Sopenharmony_ci ID STR # Hook name (see pcm_hook) 292d5ac70f0Sopenharmony_ci # or 293d5ac70f0Sopenharmony_ci ID { } # Hook definition (see pcm_hook) 294d5ac70f0Sopenharmony_ci } 295d5ac70f0Sopenharmony_ci} 296d5ac70f0Sopenharmony_ci\endcode 297d5ac70f0Sopenharmony_ci 298d5ac70f0Sopenharmony_ciExample: 299d5ac70f0Sopenharmony_ci 300d5ac70f0Sopenharmony_ci\code 301d5ac70f0Sopenharmony_ci hooks.0 { 302d5ac70f0Sopenharmony_ci type ctl_elems 303d5ac70f0Sopenharmony_ci hook_args [ 304d5ac70f0Sopenharmony_ci { 305d5ac70f0Sopenharmony_ci name "Wave Surround Playback Volume" 306d5ac70f0Sopenharmony_ci preserve true 307d5ac70f0Sopenharmony_ci lock true 308d5ac70f0Sopenharmony_ci optional true 309d5ac70f0Sopenharmony_ci value [ 0 0 ] 310d5ac70f0Sopenharmony_ci } 311d5ac70f0Sopenharmony_ci { 312d5ac70f0Sopenharmony_ci name "EMU10K1 PCM Send Volume" 313d5ac70f0Sopenharmony_ci index { @func private_pcm_subdevice } 314d5ac70f0Sopenharmony_ci lock true 315d5ac70f0Sopenharmony_ci value [ 0 0 0 0 0 0 255 0 0 0 0 255 ] 316d5ac70f0Sopenharmony_ci } 317d5ac70f0Sopenharmony_ci ] 318d5ac70f0Sopenharmony_ci } 319d5ac70f0Sopenharmony_ci\endcode 320d5ac70f0Sopenharmony_ciHere, the controls "Wave Surround Playback Volume" and "EMU10K1 PCM Send Volume" 321d5ac70f0Sopenharmony_ciare set to the given values when this pcm is accessed. Since these controls 322d5ac70f0Sopenharmony_citake multi-dimensional values, the <code>value</code> field is written as 323d5ac70f0Sopenharmony_cian array. 324d5ac70f0Sopenharmony_ciWhen <code>preserve</code> is true, the old values are saved and restored 325d5ac70f0Sopenharmony_ciwhen the pcm is closed. The <code>lock</code> means that the control is 326d5ac70f0Sopenharmony_cilocked during this pcm is opened, and cannot be changed by others. 327d5ac70f0Sopenharmony_ciWhen <code>optional</code> is set, no error is returned but ignored 328d5ac70f0Sopenharmony_cieven if the specified control doesn't exist. 329d5ac70f0Sopenharmony_ci 330d5ac70f0Sopenharmony_ci\subsection pcm_plugins_hooks_funcref Function reference 331d5ac70f0Sopenharmony_ci 332d5ac70f0Sopenharmony_ci<UL> 333d5ac70f0Sopenharmony_ci <LI>The function ctl_elems - _snd_pcm_hook_ctl_elems_install() - installs 334d5ac70f0Sopenharmony_ci CTL settings described by given configuration. 335d5ac70f0Sopenharmony_ci <LI>snd_pcm_hooks_open() 336d5ac70f0Sopenharmony_ci <LI>_snd_pcm_hooks_open() 337d5ac70f0Sopenharmony_ci</UL> 338d5ac70f0Sopenharmony_ci 339d5ac70f0Sopenharmony_ci*/ 340d5ac70f0Sopenharmony_ci 341d5ac70f0Sopenharmony_cistatic int snd_pcm_hook_add_conf(snd_pcm_t *pcm, snd_config_t *root, snd_config_t *conf) 342d5ac70f0Sopenharmony_ci{ 343d5ac70f0Sopenharmony_ci int err; 344d5ac70f0Sopenharmony_ci char buf[256], errbuf[256]; 345d5ac70f0Sopenharmony_ci const char *str, *id; 346d5ac70f0Sopenharmony_ci const char *lib = NULL, *install = NULL; 347d5ac70f0Sopenharmony_ci snd_config_t *type = NULL, *args = NULL; 348d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 349d5ac70f0Sopenharmony_ci int (*install_func)(snd_pcm_t *pcm, snd_config_t *args) = NULL; 350d5ac70f0Sopenharmony_ci void *h = NULL; 351d5ac70f0Sopenharmony_ci 352d5ac70f0Sopenharmony_ci if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) { 353d5ac70f0Sopenharmony_ci SNDERR("Invalid hook definition"); 354d5ac70f0Sopenharmony_ci return -EINVAL; 355d5ac70f0Sopenharmony_ci } 356d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 357d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 358d5ac70f0Sopenharmony_ci const char *id; 359d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 360d5ac70f0Sopenharmony_ci continue; 361d5ac70f0Sopenharmony_ci if (strcmp(id, "comment") == 0) 362d5ac70f0Sopenharmony_ci continue; 363d5ac70f0Sopenharmony_ci if (strcmp(id, "type") == 0) { 364d5ac70f0Sopenharmony_ci type = n; 365d5ac70f0Sopenharmony_ci continue; 366d5ac70f0Sopenharmony_ci } 367d5ac70f0Sopenharmony_ci if (strcmp(id, "hook_args") == 0) { 368d5ac70f0Sopenharmony_ci args = n; 369d5ac70f0Sopenharmony_ci continue; 370d5ac70f0Sopenharmony_ci } 371d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 372d5ac70f0Sopenharmony_ci return -EINVAL; 373d5ac70f0Sopenharmony_ci } 374d5ac70f0Sopenharmony_ci if (!type) { 375d5ac70f0Sopenharmony_ci SNDERR("type is not defined"); 376d5ac70f0Sopenharmony_ci return -EINVAL; 377d5ac70f0Sopenharmony_ci } 378d5ac70f0Sopenharmony_ci err = snd_config_get_id(type, &id); 379d5ac70f0Sopenharmony_ci if (err < 0) { 380d5ac70f0Sopenharmony_ci SNDERR("unable to get id"); 381d5ac70f0Sopenharmony_ci return err; 382d5ac70f0Sopenharmony_ci } 383d5ac70f0Sopenharmony_ci err = snd_config_get_string(type, &str); 384d5ac70f0Sopenharmony_ci if (err < 0) { 385d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 386d5ac70f0Sopenharmony_ci return err; 387d5ac70f0Sopenharmony_ci } 388d5ac70f0Sopenharmony_ci err = snd_config_search_definition(root, "pcm_hook_type", str, &type); 389d5ac70f0Sopenharmony_ci if (err >= 0) { 390d5ac70f0Sopenharmony_ci if (snd_config_get_type(type) != SND_CONFIG_TYPE_COMPOUND) { 391d5ac70f0Sopenharmony_ci SNDERR("Invalid type for PCM type %s definition", str); 392d5ac70f0Sopenharmony_ci err = -EINVAL; 393d5ac70f0Sopenharmony_ci goto _err; 394d5ac70f0Sopenharmony_ci } 395d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, type) { 396d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 397d5ac70f0Sopenharmony_ci const char *id; 398d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 399d5ac70f0Sopenharmony_ci continue; 400d5ac70f0Sopenharmony_ci if (strcmp(id, "comment") == 0) 401d5ac70f0Sopenharmony_ci continue; 402d5ac70f0Sopenharmony_ci if (strcmp(id, "lib") == 0) { 403d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &lib); 404d5ac70f0Sopenharmony_ci if (err < 0) { 405d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 406d5ac70f0Sopenharmony_ci goto _err; 407d5ac70f0Sopenharmony_ci } 408d5ac70f0Sopenharmony_ci continue; 409d5ac70f0Sopenharmony_ci } 410d5ac70f0Sopenharmony_ci if (strcmp(id, "install") == 0) { 411d5ac70f0Sopenharmony_ci err = snd_config_get_string(n, &install); 412d5ac70f0Sopenharmony_ci if (err < 0) { 413d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 414d5ac70f0Sopenharmony_ci goto _err; 415d5ac70f0Sopenharmony_ci } 416d5ac70f0Sopenharmony_ci continue; 417d5ac70f0Sopenharmony_ci } 418d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 419d5ac70f0Sopenharmony_ci err = -EINVAL; 420d5ac70f0Sopenharmony_ci goto _err; 421d5ac70f0Sopenharmony_ci } 422d5ac70f0Sopenharmony_ci } 423d5ac70f0Sopenharmony_ci if (!install) { 424d5ac70f0Sopenharmony_ci install = buf; 425d5ac70f0Sopenharmony_ci snprintf(buf, sizeof(buf), "_snd_pcm_hook_%s_install", str); 426d5ac70f0Sopenharmony_ci } 427d5ac70f0Sopenharmony_ci h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf)); 428d5ac70f0Sopenharmony_ci install_func = h ? snd_dlsym(h, install, SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION)) : NULL; 429d5ac70f0Sopenharmony_ci err = 0; 430d5ac70f0Sopenharmony_ci if (!h) { 431d5ac70f0Sopenharmony_ci SNDERR("Cannot open shared library %s (%s)", 432d5ac70f0Sopenharmony_ci lib ? lib : "[builtin]", errbuf); 433d5ac70f0Sopenharmony_ci err = -ENOENT; 434d5ac70f0Sopenharmony_ci } else if (!install_func) { 435d5ac70f0Sopenharmony_ci SNDERR("symbol %s is not defined inside %s", install, 436d5ac70f0Sopenharmony_ci lib ? lib : "[builtin]"); 437d5ac70f0Sopenharmony_ci snd_dlclose(h); 438d5ac70f0Sopenharmony_ci err = -ENXIO; 439d5ac70f0Sopenharmony_ci } 440d5ac70f0Sopenharmony_ci _err: 441d5ac70f0Sopenharmony_ci if (type) 442d5ac70f0Sopenharmony_ci snd_config_delete(type); 443d5ac70f0Sopenharmony_ci if (err < 0) 444d5ac70f0Sopenharmony_ci return err; 445d5ac70f0Sopenharmony_ci 446d5ac70f0Sopenharmony_ci if (args && snd_config_get_string(args, &str) >= 0) { 447d5ac70f0Sopenharmony_ci err = snd_config_search_definition(root, "hook_args", str, &args); 448d5ac70f0Sopenharmony_ci if (err < 0) 449d5ac70f0Sopenharmony_ci SNDERR("unknown hook_args %s", str); 450d5ac70f0Sopenharmony_ci else 451d5ac70f0Sopenharmony_ci err = install_func(pcm, args); 452d5ac70f0Sopenharmony_ci snd_config_delete(args); 453d5ac70f0Sopenharmony_ci } else 454d5ac70f0Sopenharmony_ci err = install_func(pcm, args); 455d5ac70f0Sopenharmony_ci 456d5ac70f0Sopenharmony_ci if (err >= 0) 457d5ac70f0Sopenharmony_ci err = hook_add_dlobj(pcm, h); 458d5ac70f0Sopenharmony_ci 459d5ac70f0Sopenharmony_ci if (err < 0) { 460d5ac70f0Sopenharmony_ci if(h) 461d5ac70f0Sopenharmony_ci snd_dlclose(h); 462d5ac70f0Sopenharmony_ci return err; 463d5ac70f0Sopenharmony_ci } 464d5ac70f0Sopenharmony_ci return 0; 465d5ac70f0Sopenharmony_ci} 466d5ac70f0Sopenharmony_ci 467d5ac70f0Sopenharmony_ci/** 468d5ac70f0Sopenharmony_ci * \brief Creates a new hooks PCM 469d5ac70f0Sopenharmony_ci * \param pcmp Returns created PCM handle 470d5ac70f0Sopenharmony_ci * \param name Name of PCM 471d5ac70f0Sopenharmony_ci * \param root Root configuration node 472d5ac70f0Sopenharmony_ci * \param conf Configuration node with hooks PCM description 473d5ac70f0Sopenharmony_ci * \param stream PCM Stream 474d5ac70f0Sopenharmony_ci * \param mode PCM Mode 475d5ac70f0Sopenharmony_ci * \retval zero on success otherwise a negative error code 476d5ac70f0Sopenharmony_ci * \warning Using of this function might be dangerous in the sense 477d5ac70f0Sopenharmony_ci * of compatibility reasons. The prototype might be freely 478d5ac70f0Sopenharmony_ci * changed in future. 479d5ac70f0Sopenharmony_ci */ 480d5ac70f0Sopenharmony_ciint _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, 481d5ac70f0Sopenharmony_ci snd_config_t *root, snd_config_t *conf, 482d5ac70f0Sopenharmony_ci snd_pcm_stream_t stream, int mode) 483d5ac70f0Sopenharmony_ci{ 484d5ac70f0Sopenharmony_ci snd_config_iterator_t i, next; 485d5ac70f0Sopenharmony_ci int err; 486d5ac70f0Sopenharmony_ci snd_pcm_t *rpcm = NULL, *spcm; 487d5ac70f0Sopenharmony_ci snd_config_t *slave = NULL, *sconf; 488d5ac70f0Sopenharmony_ci snd_config_t *hooks = NULL; 489d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, conf) { 490d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 491d5ac70f0Sopenharmony_ci const char *id; 492d5ac70f0Sopenharmony_ci if (snd_config_get_id(n, &id) < 0) 493d5ac70f0Sopenharmony_ci continue; 494d5ac70f0Sopenharmony_ci if (snd_pcm_conf_generic_id(id)) 495d5ac70f0Sopenharmony_ci continue; 496d5ac70f0Sopenharmony_ci if (strcmp(id, "slave") == 0) { 497d5ac70f0Sopenharmony_ci slave = n; 498d5ac70f0Sopenharmony_ci continue; 499d5ac70f0Sopenharmony_ci } 500d5ac70f0Sopenharmony_ci if (strcmp(id, "hooks") == 0) { 501d5ac70f0Sopenharmony_ci if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) { 502d5ac70f0Sopenharmony_ci SNDERR("Invalid type for %s", id); 503d5ac70f0Sopenharmony_ci return -EINVAL; 504d5ac70f0Sopenharmony_ci } 505d5ac70f0Sopenharmony_ci hooks = n; 506d5ac70f0Sopenharmony_ci continue; 507d5ac70f0Sopenharmony_ci } 508d5ac70f0Sopenharmony_ci SNDERR("Unknown field %s", id); 509d5ac70f0Sopenharmony_ci return -EINVAL; 510d5ac70f0Sopenharmony_ci } 511d5ac70f0Sopenharmony_ci if (!slave) { 512d5ac70f0Sopenharmony_ci SNDERR("slave is not defined"); 513d5ac70f0Sopenharmony_ci return -EINVAL; 514d5ac70f0Sopenharmony_ci } 515d5ac70f0Sopenharmony_ci err = snd_pcm_slave_conf(root, slave, &sconf, 0); 516d5ac70f0Sopenharmony_ci if (err < 0) 517d5ac70f0Sopenharmony_ci return err; 518d5ac70f0Sopenharmony_ci err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf); 519d5ac70f0Sopenharmony_ci snd_config_delete(sconf); 520d5ac70f0Sopenharmony_ci if (err < 0) 521d5ac70f0Sopenharmony_ci return err; 522d5ac70f0Sopenharmony_ci err = snd_pcm_hooks_open(&rpcm, name, spcm, 1); 523d5ac70f0Sopenharmony_ci if (err < 0) { 524d5ac70f0Sopenharmony_ci snd_pcm_close(spcm); 525d5ac70f0Sopenharmony_ci return err; 526d5ac70f0Sopenharmony_ci } 527d5ac70f0Sopenharmony_ci if (!hooks) 528d5ac70f0Sopenharmony_ci goto _done; 529d5ac70f0Sopenharmony_ci snd_config_for_each(i, next, hooks) { 530d5ac70f0Sopenharmony_ci snd_config_t *n = snd_config_iterator_entry(i); 531d5ac70f0Sopenharmony_ci const char *str; 532d5ac70f0Sopenharmony_ci if (snd_config_get_string(n, &str) >= 0) { 533d5ac70f0Sopenharmony_ci err = snd_config_search_definition(root, "pcm_hook", str, &n); 534d5ac70f0Sopenharmony_ci if (err < 0) { 535d5ac70f0Sopenharmony_ci SNDERR("unknown pcm_hook %s", str); 536d5ac70f0Sopenharmony_ci } else { 537d5ac70f0Sopenharmony_ci err = snd_pcm_hook_add_conf(rpcm, root, n); 538d5ac70f0Sopenharmony_ci snd_config_delete(n); 539d5ac70f0Sopenharmony_ci } 540d5ac70f0Sopenharmony_ci } else 541d5ac70f0Sopenharmony_ci err = snd_pcm_hook_add_conf(rpcm, root, n); 542d5ac70f0Sopenharmony_ci if (err < 0) { 543d5ac70f0Sopenharmony_ci snd_pcm_close(rpcm); 544d5ac70f0Sopenharmony_ci return err; 545d5ac70f0Sopenharmony_ci } 546d5ac70f0Sopenharmony_ci } 547d5ac70f0Sopenharmony_ci _done: 548d5ac70f0Sopenharmony_ci *pcmp = rpcm; 549d5ac70f0Sopenharmony_ci return 0; 550d5ac70f0Sopenharmony_ci} 551d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 552d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_hooks_open, SND_PCM_DLSYM_VERSION); 553d5ac70f0Sopenharmony_ci#endif 554d5ac70f0Sopenharmony_ci 555d5ac70f0Sopenharmony_ci/** 556d5ac70f0Sopenharmony_ci * \brief Get PCM handle for a PCM hook 557d5ac70f0Sopenharmony_ci * \param hook PCM hook handle 558d5ac70f0Sopenharmony_ci * \return PCM handle 559d5ac70f0Sopenharmony_ci */ 560d5ac70f0Sopenharmony_cisnd_pcm_t *snd_pcm_hook_get_pcm(snd_pcm_hook_t *hook) 561d5ac70f0Sopenharmony_ci{ 562d5ac70f0Sopenharmony_ci assert(hook); 563d5ac70f0Sopenharmony_ci return hook->pcm; 564d5ac70f0Sopenharmony_ci} 565d5ac70f0Sopenharmony_ci 566d5ac70f0Sopenharmony_ci/** 567d5ac70f0Sopenharmony_ci * \brief Get callback function private data for a PCM hook 568d5ac70f0Sopenharmony_ci * \param hook PCM hook handle 569d5ac70f0Sopenharmony_ci * \return callback function private data 570d5ac70f0Sopenharmony_ci */ 571d5ac70f0Sopenharmony_civoid *snd_pcm_hook_get_private(snd_pcm_hook_t *hook) 572d5ac70f0Sopenharmony_ci{ 573d5ac70f0Sopenharmony_ci assert(hook); 574d5ac70f0Sopenharmony_ci return hook->private_data; 575d5ac70f0Sopenharmony_ci} 576d5ac70f0Sopenharmony_ci 577d5ac70f0Sopenharmony_ci/** 578d5ac70f0Sopenharmony_ci * \brief Set callback function private data for a PCM hook 579d5ac70f0Sopenharmony_ci * \param hook PCM hook handle 580d5ac70f0Sopenharmony_ci * \param private_data The private data value 581d5ac70f0Sopenharmony_ci */ 582d5ac70f0Sopenharmony_civoid snd_pcm_hook_set_private(snd_pcm_hook_t *hook, void *private_data) 583d5ac70f0Sopenharmony_ci{ 584d5ac70f0Sopenharmony_ci assert(hook); 585d5ac70f0Sopenharmony_ci hook->private_data = private_data; 586d5ac70f0Sopenharmony_ci} 587d5ac70f0Sopenharmony_ci 588d5ac70f0Sopenharmony_ci/** 589d5ac70f0Sopenharmony_ci * \brief Add a PCM hook at end of hooks chain 590d5ac70f0Sopenharmony_ci * \param hookp Returned PCM hook handle 591d5ac70f0Sopenharmony_ci * \param pcm PCM handle 592d5ac70f0Sopenharmony_ci * \param type PCM hook type 593d5ac70f0Sopenharmony_ci * \param func PCM hook callback function 594d5ac70f0Sopenharmony_ci * \param private_data PCM hook private data 595d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 596d5ac70f0Sopenharmony_ci * 597d5ac70f0Sopenharmony_ci * Warning: an hook callback function cannot remove an hook of the same type 598d5ac70f0Sopenharmony_ci * different from itself 599d5ac70f0Sopenharmony_ci */ 600d5ac70f0Sopenharmony_ciint snd_pcm_hook_add(snd_pcm_hook_t **hookp, snd_pcm_t *pcm, 601d5ac70f0Sopenharmony_ci snd_pcm_hook_type_t type, 602d5ac70f0Sopenharmony_ci snd_pcm_hook_func_t func, void *private_data) 603d5ac70f0Sopenharmony_ci{ 604d5ac70f0Sopenharmony_ci snd_pcm_hook_t *h; 605d5ac70f0Sopenharmony_ci snd_pcm_hooks_t *hooks; 606d5ac70f0Sopenharmony_ci assert(hookp && func); 607d5ac70f0Sopenharmony_ci assert(snd_pcm_type(pcm) == SND_PCM_TYPE_HOOKS); 608d5ac70f0Sopenharmony_ci h = calloc(1, sizeof(*h)); 609d5ac70f0Sopenharmony_ci if (!h) 610d5ac70f0Sopenharmony_ci return -ENOMEM; 611d5ac70f0Sopenharmony_ci h->pcm = pcm; 612d5ac70f0Sopenharmony_ci h->func = func; 613d5ac70f0Sopenharmony_ci h->private_data = private_data; 614d5ac70f0Sopenharmony_ci hooks = pcm->private_data; 615d5ac70f0Sopenharmony_ci list_add_tail(&h->list, &hooks->hooks[type]); 616d5ac70f0Sopenharmony_ci *hookp = h; 617d5ac70f0Sopenharmony_ci return 0; 618d5ac70f0Sopenharmony_ci} 619d5ac70f0Sopenharmony_ci 620d5ac70f0Sopenharmony_ci/** 621d5ac70f0Sopenharmony_ci * \brief Remove a PCM hook 622d5ac70f0Sopenharmony_ci * \param hook PCM hook handle 623d5ac70f0Sopenharmony_ci * \return 0 on success otherwise a negative error code 624d5ac70f0Sopenharmony_ci * 625d5ac70f0Sopenharmony_ci * Warning: an hook callback cannot remove an hook of the same type 626d5ac70f0Sopenharmony_ci * different from itself 627d5ac70f0Sopenharmony_ci */ 628d5ac70f0Sopenharmony_ciint snd_pcm_hook_remove(snd_pcm_hook_t *hook) 629d5ac70f0Sopenharmony_ci{ 630d5ac70f0Sopenharmony_ci assert(hook); 631d5ac70f0Sopenharmony_ci list_del(&hook->list); 632d5ac70f0Sopenharmony_ci free(hook); 633d5ac70f0Sopenharmony_ci return 0; 634d5ac70f0Sopenharmony_ci} 635d5ac70f0Sopenharmony_ci 636d5ac70f0Sopenharmony_ci/* 637d5ac70f0Sopenharmony_ci * 638d5ac70f0Sopenharmony_ci */ 639d5ac70f0Sopenharmony_ci 640d5ac70f0Sopenharmony_cistatic int snd_pcm_hook_ctl_elems_hw_params(snd_pcm_hook_t *hook) 641d5ac70f0Sopenharmony_ci{ 642d5ac70f0Sopenharmony_ci snd_sctl_t *h = snd_pcm_hook_get_private(hook); 643d5ac70f0Sopenharmony_ci return snd_sctl_install(h); 644d5ac70f0Sopenharmony_ci} 645d5ac70f0Sopenharmony_ci 646d5ac70f0Sopenharmony_cistatic int snd_pcm_hook_ctl_elems_hw_free(snd_pcm_hook_t *hook) 647d5ac70f0Sopenharmony_ci{ 648d5ac70f0Sopenharmony_ci snd_sctl_t *h = snd_pcm_hook_get_private(hook); 649d5ac70f0Sopenharmony_ci return snd_sctl_remove(h); 650d5ac70f0Sopenharmony_ci} 651d5ac70f0Sopenharmony_ci 652d5ac70f0Sopenharmony_cistatic int snd_pcm_hook_ctl_elems_close(snd_pcm_hook_t *hook) 653d5ac70f0Sopenharmony_ci{ 654d5ac70f0Sopenharmony_ci snd_sctl_t *h = snd_pcm_hook_get_private(hook); 655d5ac70f0Sopenharmony_ci int err = snd_sctl_free(h); 656d5ac70f0Sopenharmony_ci snd_pcm_hook_set_private(hook, NULL); 657d5ac70f0Sopenharmony_ci return err; 658d5ac70f0Sopenharmony_ci} 659d5ac70f0Sopenharmony_ci 660d5ac70f0Sopenharmony_ci/** 661d5ac70f0Sopenharmony_ci * \brief Install CTL settings using hardware associated with PCM handle 662d5ac70f0Sopenharmony_ci * \param pcm PCM handle 663d5ac70f0Sopenharmony_ci * \param conf Configuration node with CTL settings 664d5ac70f0Sopenharmony_ci * \return zero on success otherwise a negative error code 665d5ac70f0Sopenharmony_ci */ 666d5ac70f0Sopenharmony_ciint _snd_pcm_hook_ctl_elems_install(snd_pcm_t *pcm, snd_config_t *conf) 667d5ac70f0Sopenharmony_ci{ 668d5ac70f0Sopenharmony_ci int err; 669d5ac70f0Sopenharmony_ci int card; 670d5ac70f0Sopenharmony_ci snd_pcm_info_t info = {0}; 671d5ac70f0Sopenharmony_ci char ctl_name[16]; 672d5ac70f0Sopenharmony_ci snd_ctl_t *ctl; 673d5ac70f0Sopenharmony_ci snd_sctl_t *sctl = NULL; 674d5ac70f0Sopenharmony_ci snd_config_t *pcm_conf = NULL; 675d5ac70f0Sopenharmony_ci snd_pcm_hook_t *h_hw_params = NULL, *h_hw_free = NULL, *h_close = NULL; 676d5ac70f0Sopenharmony_ci assert(conf); 677d5ac70f0Sopenharmony_ci assert(snd_config_get_type(conf) == SND_CONFIG_TYPE_COMPOUND); 678d5ac70f0Sopenharmony_ci 679d5ac70f0Sopenharmony_ci err = snd_pcm_info(pcm, &info); 680d5ac70f0Sopenharmony_ci if (err < 0) 681d5ac70f0Sopenharmony_ci return err; 682d5ac70f0Sopenharmony_ci card = snd_pcm_info_get_card(&info); 683d5ac70f0Sopenharmony_ci if (card < 0) { 684d5ac70f0Sopenharmony_ci SNDERR("No card for this PCM"); 685d5ac70f0Sopenharmony_ci return -EINVAL; 686d5ac70f0Sopenharmony_ci } 687d5ac70f0Sopenharmony_ci sprintf(ctl_name, "hw:%d", card); 688d5ac70f0Sopenharmony_ci err = snd_ctl_open(&ctl, ctl_name, 0); 689d5ac70f0Sopenharmony_ci if (err < 0) { 690d5ac70f0Sopenharmony_ci SNDERR("Cannot open CTL %s", ctl_name); 691d5ac70f0Sopenharmony_ci return err; 692d5ac70f0Sopenharmony_ci } 693d5ac70f0Sopenharmony_ci err = snd_config_imake_pointer(&pcm_conf, "pcm_handle", pcm); 694d5ac70f0Sopenharmony_ci if (err < 0) 695d5ac70f0Sopenharmony_ci goto _err; 696d5ac70f0Sopenharmony_ci err = snd_sctl_build(&sctl, ctl, conf, pcm_conf, 0); 697d5ac70f0Sopenharmony_ci if (err < 0) 698d5ac70f0Sopenharmony_ci goto _err; 699d5ac70f0Sopenharmony_ci err = snd_pcm_hook_add(&h_hw_params, pcm, SND_PCM_HOOK_TYPE_HW_PARAMS, 700d5ac70f0Sopenharmony_ci snd_pcm_hook_ctl_elems_hw_params, sctl); 701d5ac70f0Sopenharmony_ci if (err < 0) 702d5ac70f0Sopenharmony_ci goto _err; 703d5ac70f0Sopenharmony_ci err = snd_pcm_hook_add(&h_hw_free, pcm, SND_PCM_HOOK_TYPE_HW_FREE, 704d5ac70f0Sopenharmony_ci snd_pcm_hook_ctl_elems_hw_free, sctl); 705d5ac70f0Sopenharmony_ci if (err < 0) 706d5ac70f0Sopenharmony_ci goto _err; 707d5ac70f0Sopenharmony_ci err = snd_pcm_hook_add(&h_close, pcm, SND_PCM_HOOK_TYPE_CLOSE, 708d5ac70f0Sopenharmony_ci snd_pcm_hook_ctl_elems_close, sctl); 709d5ac70f0Sopenharmony_ci if (err < 0) 710d5ac70f0Sopenharmony_ci goto _err; 711d5ac70f0Sopenharmony_ci snd_config_delete(pcm_conf); 712d5ac70f0Sopenharmony_ci return 0; 713d5ac70f0Sopenharmony_ci _err: 714d5ac70f0Sopenharmony_ci if (h_hw_params) 715d5ac70f0Sopenharmony_ci snd_pcm_hook_remove(h_hw_params); 716d5ac70f0Sopenharmony_ci if (h_hw_free) 717d5ac70f0Sopenharmony_ci snd_pcm_hook_remove(h_hw_free); 718d5ac70f0Sopenharmony_ci if (h_close) 719d5ac70f0Sopenharmony_ci snd_pcm_hook_remove(h_close); 720d5ac70f0Sopenharmony_ci if (sctl) 721d5ac70f0Sopenharmony_ci snd_sctl_free(sctl); 722d5ac70f0Sopenharmony_ci if (pcm_conf) 723d5ac70f0Sopenharmony_ci snd_config_delete(pcm_conf); 724d5ac70f0Sopenharmony_ci return err; 725d5ac70f0Sopenharmony_ci} 726d5ac70f0Sopenharmony_ci#ifndef DOC_HIDDEN 727d5ac70f0Sopenharmony_ciSND_DLSYM_BUILD_VERSION(_snd_pcm_hook_ctl_elems_install, SND_PCM_DLSYM_VERSION); 728d5ac70f0Sopenharmony_ci#endif 729