Blame src/pcm/pcm_hooks.c

Packit 4a16fb
/**
Packit 4a16fb
 * \file pcm/pcm_hooks.c
Packit 4a16fb
 * \ingroup PCM_Hook
Packit 4a16fb
 * \brief PCM Hook Interface
Packit 4a16fb
 * \author Abramo Bagnara <abramo@alsa-project.org>
Packit 4a16fb
 * \author Jaroslav Kysela <perex@perex.cz>
Packit 4a16fb
 * \date 2000-2001
Packit 4a16fb
 */
Packit 4a16fb
/*
Packit 4a16fb
 *  PCM - Hook functions
Packit 4a16fb
 *  Copyright (c) 2001 by Abramo Bagnara <abramo@alsa-project.org>
Packit 4a16fb
 *
Packit 4a16fb
 *
Packit 4a16fb
 *   This library is free software; you can redistribute it and/or modify
Packit 4a16fb
 *   it under the terms of the GNU Lesser General Public License as
Packit 4a16fb
 *   published by the Free Software Foundation; either version 2.1 of
Packit 4a16fb
 *   the License, or (at your option) any later version.
Packit 4a16fb
 *
Packit 4a16fb
 *   This program is distributed in the hope that it will be useful,
Packit 4a16fb
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4a16fb
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 4a16fb
 *   GNU Lesser General Public License for more details.
Packit 4a16fb
 *
Packit 4a16fb
 *   You should have received a copy of the GNU Lesser General Public
Packit 4a16fb
 *   License along with this library; if not, write to the Free Software
Packit 4a16fb
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
Packit 4a16fb
 *
Packit 4a16fb
 */
Packit 4a16fb
  
Packit 4a16fb
#include "pcm_local.h"
Packit 4a16fb
#include "pcm_generic.h"
Packit 4a16fb
Packit 4a16fb
#ifndef PIC
Packit 4a16fb
/* entry for static linking */
Packit 4a16fb
const char *_snd_module_pcm_hooks = "";
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
#ifndef DOC_HIDDEN
Packit 4a16fb
struct _snd_pcm_hook {
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	snd_pcm_hook_func_t func;
Packit 4a16fb
	void *private_data;
Packit 4a16fb
	struct list_head list;
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
struct snd_pcm_hook_dllist {
Packit 4a16fb
	void *dlobj;
Packit 4a16fb
	struct list_head list;
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
typedef struct {
Packit 4a16fb
	snd_pcm_generic_t gen;
Packit 4a16fb
	struct list_head hooks[SND_PCM_HOOK_TYPE_LAST + 1];
Packit 4a16fb
	struct list_head dllist;
Packit 4a16fb
} snd_pcm_hooks_t;
Packit 4a16fb
#endif
Packit 4a16fb
Packit 4a16fb
static int hook_add_dlobj(snd_pcm_t *pcm, void *dlobj)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_hooks_t *h = pcm->private_data;
Packit 4a16fb
	struct snd_pcm_hook_dllist *dl;
Packit 4a16fb
Packit 4a16fb
	dl = malloc(sizeof(*dl));
Packit 4a16fb
	if (!dl)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
Packit 4a16fb
	dl->dlobj = dlobj;
Packit 4a16fb
	list_add_tail(&dl->list, &h->dllist);
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void hook_remove_dlobj(struct snd_pcm_hook_dllist *dl)
Packit 4a16fb
{
Packit 4a16fb
	list_del(&dl->list);
Packit 4a16fb
	snd_dlclose(dl->dlobj);
Packit 4a16fb
	free(dl);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_hooks_close(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_hooks_t *h = pcm->private_data;
Packit 4a16fb
	struct list_head *pos, *next;
Packit 4a16fb
	unsigned int k;
Packit 4a16fb
	int res = 0, err;
Packit 4a16fb
Packit 4a16fb
	list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_CLOSE]) {
Packit 4a16fb
		snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list);
Packit 4a16fb
		err = hook->func(hook);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			res = err;
Packit 4a16fb
	}
Packit 4a16fb
	for (k = 0; k <= SND_PCM_HOOK_TYPE_LAST; ++k) {
Packit 4a16fb
		struct list_head *hooks = &h->hooks[k];
Packit 4a16fb
		while (!list_empty(hooks)) {
Packit 4a16fb
			snd_pcm_hook_t *hook;
Packit 4a16fb
			pos = hooks->next;
Packit 4a16fb
			hook = list_entry(pos, snd_pcm_hook_t, list);
Packit 4a16fb
			snd_pcm_hook_remove(hook);
Packit 4a16fb
		}
Packit 4a16fb
	}
Packit 4a16fb
	while (!list_empty(&h->dllist)) {
Packit 4a16fb
		pos = h->dllist.next;
Packit 4a16fb
		hook_remove_dlobj(list_entry(pos, struct snd_pcm_hook_dllist, list));
Packit 4a16fb
	}
Packit 4a16fb
	err = snd_pcm_generic_close(pcm);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		res = err;
Packit 4a16fb
	return res;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_hooks_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_hooks_t *h = pcm->private_data;
Packit 4a16fb
	struct list_head *pos, *next;
Packit 4a16fb
	int err = snd_pcm_generic_hw_params(pcm, params);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_HW_PARAMS]) {
Packit 4a16fb
		snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list);
Packit 4a16fb
		err = hook->func(hook);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static int snd_pcm_hooks_hw_free(snd_pcm_t *pcm)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_hooks_t *h = pcm->private_data;
Packit 4a16fb
	struct list_head *pos, *next;
Packit 4a16fb
	int err = snd_pcm_generic_hw_free(pcm);
Packit 4a16fb
	if (err < 0)
Packit 4a16fb
		return err;
Packit 4a16fb
	list_for_each_safe(pos, next, &h->hooks[SND_PCM_HOOK_TYPE_HW_FREE]) {
Packit 4a16fb
		snd_pcm_hook_t *hook = list_entry(pos, snd_pcm_hook_t, list);
Packit 4a16fb
		err = hook->func(hook);
Packit 4a16fb
		if (err < 0)
Packit 4a16fb
			return err;
Packit 4a16fb
	}
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static void snd_pcm_hooks_dump(snd_pcm_t *pcm, snd_output_t *out)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_hooks_t *h = pcm->private_data;
Packit 4a16fb
	snd_output_printf(out, "Hooks PCM\n");
Packit 4a16fb
	if (pcm->setup) {
Packit 4a16fb
		snd_output_printf(out, "Its setup is:\n");
Packit 4a16fb
		snd_pcm_dump_setup(pcm, out);
Packit 4a16fb
	}
Packit 4a16fb
	snd_output_printf(out, "Slave: ");
Packit 4a16fb
	snd_pcm_dump(h->gen.slave, out);
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_ops_t snd_pcm_hooks_ops = {
Packit 4a16fb
	.close = snd_pcm_hooks_close,
Packit 4a16fb
	.info = snd_pcm_generic_info,
Packit 4a16fb
	.hw_refine = snd_pcm_generic_hw_refine,
Packit 4a16fb
	.hw_params = snd_pcm_hooks_hw_params,
Packit 4a16fb
	.hw_free = snd_pcm_hooks_hw_free,
Packit 4a16fb
	.sw_params = snd_pcm_generic_sw_params,
Packit 4a16fb
	.channel_info = snd_pcm_generic_channel_info,
Packit 4a16fb
	.dump = snd_pcm_hooks_dump,
Packit 4a16fb
	.nonblock = snd_pcm_generic_nonblock,
Packit 4a16fb
	.async = snd_pcm_generic_async,
Packit 4a16fb
	.mmap = snd_pcm_generic_mmap,
Packit 4a16fb
	.munmap = snd_pcm_generic_munmap,
Packit 4a16fb
	.query_chmaps = snd_pcm_generic_query_chmaps,
Packit 4a16fb
	.get_chmap = snd_pcm_generic_get_chmap,
Packit 4a16fb
	.set_chmap = snd_pcm_generic_set_chmap,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
static const snd_pcm_fast_ops_t snd_pcm_hooks_fast_ops = {
Packit 4a16fb
	.status = snd_pcm_generic_status,
Packit 4a16fb
	.state = snd_pcm_generic_state,
Packit 4a16fb
	.hwsync = snd_pcm_generic_hwsync,
Packit 4a16fb
	.delay = snd_pcm_generic_delay,
Packit 4a16fb
	.prepare = snd_pcm_generic_prepare,
Packit 4a16fb
	.reset = snd_pcm_generic_reset,
Packit 4a16fb
	.start = snd_pcm_generic_start,
Packit 4a16fb
	.drop = snd_pcm_generic_drop,
Packit 4a16fb
	.drain = snd_pcm_generic_drain,
Packit 4a16fb
	.pause = snd_pcm_generic_pause,
Packit 4a16fb
	.rewindable = snd_pcm_generic_rewindable,
Packit 4a16fb
	.rewind = snd_pcm_generic_rewind,
Packit 4a16fb
	.forwardable = snd_pcm_generic_forwardable,
Packit 4a16fb
	.forward = snd_pcm_generic_forward,
Packit 4a16fb
	.resume = snd_pcm_generic_resume,
Packit 4a16fb
	.link = snd_pcm_generic_link,
Packit 4a16fb
	.link_slaves = snd_pcm_generic_link_slaves,
Packit 4a16fb
	.unlink = snd_pcm_generic_unlink,
Packit 4a16fb
	.writei = snd_pcm_generic_writei,
Packit 4a16fb
	.writen = snd_pcm_generic_writen,
Packit 4a16fb
	.readi = snd_pcm_generic_readi,
Packit 4a16fb
	.readn = snd_pcm_generic_readn,
Packit 4a16fb
	.avail_update = snd_pcm_generic_avail_update,
Packit 4a16fb
	.mmap_commit = snd_pcm_generic_mmap_commit,
Packit 4a16fb
	.htimestamp = snd_pcm_generic_htimestamp,
Packit 4a16fb
	.poll_descriptors_count = snd_pcm_generic_poll_descriptors_count,
Packit 4a16fb
	.poll_descriptors = snd_pcm_generic_poll_descriptors,
Packit 4a16fb
	.poll_revents = snd_pcm_generic_poll_revents,
Packit 4a16fb
	.may_wait_for_avail_min = snd_pcm_generic_may_wait_for_avail_min,
Packit 4a16fb
};
Packit 4a16fb
Packit 4a16fb
/**
Packit 4a16fb
 * \brief Creates a new hooks PCM
Packit 4a16fb
 * \param pcmp Returns created PCM handle
Packit 4a16fb
 * \param name Name of PCM
Packit 4a16fb
 * \param slave Slave PCM
Packit 4a16fb
 * \param close_slave If set, slave PCM handle is closed when hooks PCM is closed
Packit 4a16fb
 * \retval zero on success otherwise a negative error code
Packit 4a16fb
 * \warning Using of this function might be dangerous in the sense
Packit 4a16fb
 *          of compatibility reasons. The prototype might be freely
Packit 4a16fb
 *	    changed in future.
Packit 4a16fb
 */
Packit 4a16fb
int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int close_slave)
Packit 4a16fb
{
Packit 4a16fb
	snd_pcm_t *pcm;
Packit 4a16fb
	snd_pcm_hooks_t *h;
Packit 4a16fb
	unsigned int k;
Packit 4a16fb
	int err;
Packit 4a16fb
	assert(pcmp && slave);
Packit 4a16fb
	h = calloc(1, sizeof(snd_pcm_hooks_t));
Packit 4a16fb
	if (!h)
Packit 4a16fb
		return -ENOMEM;
Packit 4a16fb
	h->gen.slave = slave;
Packit 4a16fb
	h->gen.close_slave = close_slave;
Packit 4a16fb
	for (k = 0; k <= SND_PCM_HOOK_TYPE_LAST; ++k) {
Packit 4a16fb
		INIT_LIST_HEAD(&h->hooks[k]);
Packit 4a16fb
	}
Packit 4a16fb
	INIT_LIST_HEAD(&h->dllist);
Packit 4a16fb
	err = snd_pcm_new(&pcm, SND_PCM_TYPE_HOOKS, name, slave->stream, slave->mode);
Packit 4a16fb
	if (err < 0) {
Packit 4a16fb
		free(h);
Packit 4a16fb
		return err;
Packit 4a16fb
	}
Packit 4a16fb
	pcm->ops = &snd_pcm_hooks_ops;
Packit 4a16fb
	pcm->fast_ops = &snd_pcm_hooks_fast_ops;
Packit 4a16fb
	pcm->private_data = h;
Packit 4a16fb
	pcm->poll_fd = slave->poll_fd;
Packit 4a16fb
	pcm->poll_events = slave->poll_events;
Packit 4a16fb
	pcm->mmap_shadow = 1;
Packit 4a16fb
	pcm->tstamp_type = slave->tstamp_type;
Packit 4a16fb
	snd_pcm_link_hw_ptr(pcm, slave);
Packit 4a16fb
	snd_pcm_link_appl_ptr(pcm, slave);
Packit 4a16fb
	*pcmp = pcm;
Packit 4a16fb
Packit 4a16fb
	return 0;
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
/*! \page pcm_plugins
Packit 4a16fb
Packit 4a16fb
\section pcm_plugins_hooks Plugin: hooks
Packit 4a16fb
Packit 4a16fb
This plugin is used to call some 'hook' function when this plugin is opened,
Packit 4a16fb
modified or closed.
Packit 4a16fb
Typically, it is used to change control values for a certain state
Packit 4a16fb
specially for the PCM (see the example below).
Packit 4a16fb
Packit 4a16fb
\code
Packit 4a16fb
# Hook arguments definition
Packit 4a16fb
hook_args.NAME {
Packit 4a16fb
	...			# Arbitrary arguments
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
# PCM hook type
Packit 4a16fb
pcm_hook_type.NAME {
Packit 4a16fb
	[lib STR]		# Library file (default libasound.so)
Packit 4a16fb
	[install STR]		# Install function (default _snd_pcm_hook_NAME_install)
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
# PCM hook definition
Packit 4a16fb
pcm_hook.NAME {
Packit 4a16fb
	type STR		# PCM Hook type (see pcm_hook_type)
Packit 4a16fb
	[args STR]		# Arguments for install function (see hook_args)
Packit 4a16fb
	# or
Packit 4a16fb
	[args { }]		# Arguments for install function
Packit 4a16fb
}
Packit 4a16fb
Packit 4a16fb
# PCM hook plugin
Packit 4a16fb
pcm.NAME {
Packit 4a16fb
	type hooks		# PCM with hooks
Packit 4a16fb
	slave STR		# Slave name
Packit 4a16fb
	# or
Packit 4a16fb
	slave {			# Slave definition
Packit 4a16fb
	  	pcm STR		# Slave PCM name
Packit 4a16fb
		# or
Packit 4a16fb
	  	pcm { }		# Slave PCM definition
Packit 4a16fb
	}
Packit 4a16fb
	hooks {
Packit 4a16fb
		ID STR		# Hook name (see pcm_hook)
Packit 4a16fb
		# or
Packit 4a16fb
		ID { }		# Hook definition (see pcm_hook)
Packit 4a16fb
	}
Packit 4a16fb
}
Packit 4a16fb
\endcode
Packit 4a16fb
Packit 4a16fb
Example:
Packit 4a16fb
Packit 4a16fb
\code
Packit 4a16fb
	hooks.0 {
Packit 4a16fb
		type ctl_elems
Packit 4a16fb
		hook_args [
Packit 4a16fb
			{
Packit 4a16fb
				name "Wave Surround Playback Volume"
Packit 4a16fb
				preserve true
Packit 4a16fb
				lock true
Packit 4a16fb
				optional true
Packit 4a16fb
				value [ 0 0 ]
Packit 4a16fb
			}
Packit 4a16fb
			{
Packit 4a16fb
				name "EMU10K1 PCM Send Volume"
Packit 4a16fb
				index { @func private_pcm_subdevice }
Packit 4a16fb
				lock true
Packit 4a16fb
				value [ 0 0 0 0 0 0 255 0 0 0 0 255 ]
Packit 4a16fb
			}
Packit 4a16fb
		]
Packit 4a16fb
	}
Packit 4a16fb
\endcode
Packit 4a16fb
Here, the controls "Wave Surround Playback Volume" and "EMU10K1 PCM Send Volume"
Packit 4a16fb
are set to the given values when this pcm is accessed.  Since these controls
Packit 4a16fb
take multi-dimensional values, the value field is written as
Packit 4a16fb
an array.
Packit 4a16fb
When preserve is true, the old values are saved and restored
Packit 4a16fb
when the pcm is closed.  The lock means that the control is
Packit 4a16fb
locked during this pcm is opened, and cannot be changed by others.
Packit 4a16fb
When optional is set, no error is returned but ignored
Packit 4a16fb
even if the specified control doesn't exist.
Packit 4a16fb
Packit 4a16fb
\subsection pcm_plugins_hooks_funcref Function reference
Packit 4a16fb
Packit 4a16fb
    Packit 4a16fb
      
  • The function ctl_elems - _snd_pcm_hook_ctl_elems_install() - installs
  • Packit 4a16fb
          CTL settings described by given configuration.
    Packit 4a16fb
      
  • snd_pcm_hooks_open()
  • Packit 4a16fb
      
  • _snd_pcm_hooks_open()
  • Packit 4a16fb
    Packit 4a16fb
    Packit 4a16fb
    */
    Packit 4a16fb
    Packit 4a16fb
    static int snd_pcm_hook_add_conf(snd_pcm_t *pcm, snd_config_t *root, snd_config_t *conf)
    Packit 4a16fb
    {
    Packit 4a16fb
    	int err;
    Packit 4a16fb
    	char buf[256], errbuf[256];
    Packit 4a16fb
    	const char *str, *id;
    Packit 4a16fb
    	const char *lib = NULL, *install = NULL;
    Packit 4a16fb
    	snd_config_t *type = NULL, *args = NULL;
    Packit 4a16fb
    	snd_config_iterator_t i, next;
    Packit 4a16fb
    	int (*install_func)(snd_pcm_t *pcm, snd_config_t *args) = NULL;
    Packit 4a16fb
    	void *h = NULL;
    Packit 4a16fb
    Packit 4a16fb
    	if (snd_config_get_type(conf) != SND_CONFIG_TYPE_COMPOUND) {
    Packit 4a16fb
    		SNDERR("Invalid hook definition");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	snd_config_for_each(i, next, conf) {
    Packit 4a16fb
    		snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (strcmp(id, "comment") == 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (strcmp(id, "type") == 0) {
    Packit 4a16fb
    			type = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if (strcmp(id, "hook_args") == 0) {
    Packit 4a16fb
    			args = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		SNDERR("Unknown field %s", id);
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!type) {
    Packit 4a16fb
    		SNDERR("type is not defined");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_config_get_id(type, &id;;
    Packit 4a16fb
    	if (err < 0) {
    Packit 4a16fb
    		SNDERR("unable to get id");
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_config_get_string(type, &str);
    Packit 4a16fb
    	if (err < 0) {
    Packit 4a16fb
    		SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_config_search_definition(root, "pcm_hook_type", str, &type);
    Packit 4a16fb
    	if (err >= 0) {
    Packit 4a16fb
    		if (snd_config_get_type(type) != SND_CONFIG_TYPE_COMPOUND) {
    Packit 4a16fb
    			SNDERR("Invalid type for PCM type %s definition", str);
    Packit 4a16fb
    			err = -EINVAL;
    Packit 4a16fb
    			goto _err;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		snd_config_for_each(i, next, type) {
    Packit 4a16fb
    			snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    			const char *id;
    Packit 4a16fb
    			if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			if (strcmp(id, "comment") == 0)
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			if (strcmp(id, "lib") == 0) {
    Packit 4a16fb
    				err = snd_config_get_string(n, &lib);
    Packit 4a16fb
    				if (err < 0) {
    Packit 4a16fb
    					SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    					goto _err;
    Packit 4a16fb
    				}
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			if (strcmp(id, "install") == 0) {
    Packit 4a16fb
    				err = snd_config_get_string(n, &install);
    Packit 4a16fb
    				if (err < 0) {
    Packit 4a16fb
    					SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    					goto _err;
    Packit 4a16fb
    				}
    Packit 4a16fb
    				continue;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			SNDERR("Unknown field %s", id);
    Packit 4a16fb
    			err = -EINVAL;
    Packit 4a16fb
    			goto _err;
    Packit 4a16fb
    		}
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!install) {
    Packit 4a16fb
    		install = buf;
    Packit 4a16fb
    		snprintf(buf, sizeof(buf), "_snd_pcm_hook_%s_install", str);
    Packit 4a16fb
    	}
    Packit 4a16fb
    	h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
    Packit 4a16fb
    	install_func = h ? snd_dlsym(h, install, SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION)) : NULL;
    Packit 4a16fb
    	err = 0;
    Packit 4a16fb
    	if (!h) {
    Packit 4a16fb
    		SNDERR("Cannot open shared library %s (%s)",
    Packit 4a16fb
    		       lib ? lib : "[builtin]", errbuf);
    Packit 4a16fb
    		err = -ENOENT;
    Packit 4a16fb
    	} else if (!install_func) {
    Packit 4a16fb
    		SNDERR("symbol %s is not defined inside %s", install,
    Packit 4a16fb
    		       lib ? lib : "[builtin]");
    Packit 4a16fb
    		snd_dlclose(h);
    Packit 4a16fb
    		err = -ENXIO;
    Packit 4a16fb
    	}
    Packit 4a16fb
           _err:
    Packit 4a16fb
    	if (type)
    Packit 4a16fb
    		snd_config_delete(type);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    Packit 4a16fb
    	if (args && snd_config_get_string(args, &str) >= 0) {
    Packit 4a16fb
    		err = snd_config_search_definition(root, "hook_args", str, &args);
    Packit 4a16fb
    		if (err < 0)
    Packit 4a16fb
    			SNDERR("unknown hook_args %s", str);
    Packit 4a16fb
    		else
    Packit 4a16fb
    			err = install_func(pcm, args);
    Packit 4a16fb
    		snd_config_delete(args);
    Packit 4a16fb
    	} else
    Packit 4a16fb
    		err = install_func(pcm, args);
    Packit 4a16fb
    Packit 4a16fb
    	if (err >= 0)
    Packit 4a16fb
    		err = hook_add_dlobj(pcm, h);
    Packit 4a16fb
    Packit 4a16fb
    	if (err < 0) {
    Packit 4a16fb
    		if(h)
    Packit 4a16fb
    			snd_dlclose(h);
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	return 0;
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Creates a new hooks PCM
    Packit 4a16fb
     * \param pcmp Returns created PCM handle
    Packit 4a16fb
     * \param name Name of PCM
    Packit 4a16fb
     * \param root Root configuration node
    Packit 4a16fb
     * \param conf Configuration node with hooks PCM description
    Packit 4a16fb
     * \param stream PCM Stream
    Packit 4a16fb
     * \param mode PCM Mode
    Packit 4a16fb
     * \retval zero on success otherwise a negative error code
    Packit 4a16fb
     * \warning Using of this function might be dangerous in the sense
    Packit 4a16fb
     *          of compatibility reasons. The prototype might be freely
    Packit 4a16fb
     *	    changed in future.
    Packit 4a16fb
     */
    Packit 4a16fb
    int _snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name,
    Packit 4a16fb
    			snd_config_t *root, snd_config_t *conf, 
    Packit 4a16fb
    			snd_pcm_stream_t stream, int mode)
    Packit 4a16fb
    {
    Packit 4a16fb
    	snd_config_iterator_t i, next;
    Packit 4a16fb
    	int err;
    Packit 4a16fb
    	snd_pcm_t *rpcm = NULL, *spcm;
    Packit 4a16fb
    	snd_config_t *slave = NULL, *sconf;
    Packit 4a16fb
    	snd_config_t *hooks = NULL;
    Packit 4a16fb
    	snd_config_for_each(i, next, conf) {
    Packit 4a16fb
    		snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *id;
    Packit 4a16fb
    		if (snd_config_get_id(n, &id) < 0)
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (snd_pcm_conf_generic_id(id))
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		if (strcmp(id, "slave") == 0) {
    Packit 4a16fb
    			slave = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		if (strcmp(id, "hooks") == 0) {
    Packit 4a16fb
    			if (snd_config_get_type(n) != SND_CONFIG_TYPE_COMPOUND) {
    Packit 4a16fb
    				SNDERR("Invalid type for %s", id);
    Packit 4a16fb
    				return -EINVAL;
    Packit 4a16fb
    			}
    Packit 4a16fb
    			hooks = n;
    Packit 4a16fb
    			continue;
    Packit 4a16fb
    		}
    Packit 4a16fb
    		SNDERR("Unknown field %s", id);
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!slave) {
    Packit 4a16fb
    		SNDERR("slave is not defined");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_pcm_slave_conf(root, slave, &sconf, 0);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	err = snd_pcm_open_slave(&spcm, root, sconf, stream, mode, conf);
    Packit 4a16fb
    	snd_config_delete(sconf);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	err = snd_pcm_hooks_open(&rpcm, name, spcm, 1);
    Packit 4a16fb
    	if (err < 0) {
    Packit 4a16fb
    		snd_pcm_close(spcm);
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	if (!hooks)
    Packit 4a16fb
    		goto _done;
    Packit 4a16fb
    	snd_config_for_each(i, next, hooks) {
    Packit 4a16fb
    		snd_config_t *n = snd_config_iterator_entry(i);
    Packit 4a16fb
    		const char *str;
    Packit 4a16fb
    		if (snd_config_get_string(n, &str) >= 0) {
    Packit 4a16fb
    			err = snd_config_search_definition(root, "pcm_hook", str, &n);
    Packit 4a16fb
    			if (err < 0) {
    Packit 4a16fb
    				SNDERR("unknown pcm_hook %s", str);
    Packit 4a16fb
    			} else {
    Packit 4a16fb
    				err = snd_pcm_hook_add_conf(rpcm, root, n);
    Packit 4a16fb
    				snd_config_delete(n);
    Packit 4a16fb
    			}
    Packit 4a16fb
    		} else
    Packit 4a16fb
    			err = snd_pcm_hook_add_conf(rpcm, root, n);
    Packit 4a16fb
    		if (err < 0) {
    Packit 4a16fb
    			snd_pcm_close(rpcm);
    Packit 4a16fb
    			return err;
    Packit 4a16fb
    		}
    Packit 4a16fb
    	}
    Packit 4a16fb
     _done:
    Packit 4a16fb
    	*pcmp = rpcm;
    Packit 4a16fb
    	return 0;
    Packit 4a16fb
    }
    Packit 4a16fb
    #ifndef DOC_HIDDEN
    Packit 4a16fb
    SND_DLSYM_BUILD_VERSION(_snd_pcm_hooks_open, SND_PCM_DLSYM_VERSION);
    Packit 4a16fb
    #endif
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Get PCM handle for a PCM hook
    Packit 4a16fb
     * \param hook PCM hook handle
    Packit 4a16fb
     * \return PCM handle
    Packit 4a16fb
     */
    Packit 4a16fb
    snd_pcm_t *snd_pcm_hook_get_pcm(snd_pcm_hook_t *hook)
    Packit 4a16fb
    {
    Packit 4a16fb
    	assert(hook);
    Packit 4a16fb
    	return hook->pcm;
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Get callback function private data for a PCM hook
    Packit 4a16fb
     * \param hook PCM hook handle
    Packit 4a16fb
     * \return callback function private data
    Packit 4a16fb
     */
    Packit 4a16fb
    void *snd_pcm_hook_get_private(snd_pcm_hook_t *hook)
    Packit 4a16fb
    {
    Packit 4a16fb
    	assert(hook);
    Packit 4a16fb
    	return hook->private_data;
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Set callback function private data for a PCM hook
    Packit 4a16fb
     * \param hook PCM hook handle
    Packit 4a16fb
     * \param private_data The private data value
    Packit 4a16fb
     */
    Packit 4a16fb
    void snd_pcm_hook_set_private(snd_pcm_hook_t *hook, void *private_data)
    Packit 4a16fb
    {
    Packit 4a16fb
    	assert(hook);
    Packit 4a16fb
    	hook->private_data = private_data;
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Add a PCM hook at end of hooks chain
    Packit 4a16fb
     * \param hookp Returned PCM hook handle
    Packit 4a16fb
     * \param pcm PCM handle
    Packit 4a16fb
     * \param type PCM hook type
    Packit 4a16fb
     * \param func PCM hook callback function
    Packit 4a16fb
     * \param private_data PCM hook private data
    Packit 4a16fb
     * \return 0 on success otherwise a negative error code
    Packit 4a16fb
     *
    Packit 4a16fb
     * Warning: an hook callback function cannot remove an hook of the same type
    Packit 4a16fb
     * different from itself
    Packit 4a16fb
     */
    Packit 4a16fb
    int snd_pcm_hook_add(snd_pcm_hook_t **hookp, snd_pcm_t *pcm,
    Packit 4a16fb
    		     snd_pcm_hook_type_t type,
    Packit 4a16fb
    		     snd_pcm_hook_func_t func, void *private_data)
    Packit 4a16fb
    {
    Packit 4a16fb
    	snd_pcm_hook_t *h;
    Packit 4a16fb
    	snd_pcm_hooks_t *hooks;
    Packit 4a16fb
    	assert(hookp && func);
    Packit 4a16fb
    	assert(snd_pcm_type(pcm) == SND_PCM_TYPE_HOOKS);
    Packit 4a16fb
    	h = calloc(1, sizeof(*h));
    Packit 4a16fb
    	if (!h)
    Packit 4a16fb
    		return -ENOMEM;
    Packit 4a16fb
    	h->pcm = pcm;
    Packit 4a16fb
    	h->func = func;
    Packit 4a16fb
    	h->private_data = private_data;
    Packit 4a16fb
    	hooks = pcm->private_data;
    Packit 4a16fb
    	list_add_tail(&h->list, &hooks->hooks[type]);
    Packit 4a16fb
    	*hookp = h;
    Packit 4a16fb
    	return 0;
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Remove a PCM hook
    Packit 4a16fb
     * \param hook PCM hook handle
    Packit 4a16fb
     * \return 0 on success otherwise a negative error code
    Packit 4a16fb
     *
    Packit 4a16fb
     * Warning: an hook callback cannot remove an hook of the same type
    Packit 4a16fb
     * different from itself
    Packit 4a16fb
     */
    Packit 4a16fb
    int snd_pcm_hook_remove(snd_pcm_hook_t *hook)
    Packit 4a16fb
    {
    Packit 4a16fb
    	assert(hook);
    Packit 4a16fb
    	list_del(&hook->list);
    Packit 4a16fb
    	free(hook);
    Packit 4a16fb
    	return 0;
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    /*
    Packit 4a16fb
     *
    Packit 4a16fb
     */
    Packit 4a16fb
    Packit 4a16fb
    static int snd_pcm_hook_ctl_elems_hw_params(snd_pcm_hook_t *hook)
    Packit 4a16fb
    {
    Packit 4a16fb
    	snd_sctl_t *h = snd_pcm_hook_get_private(hook);
    Packit 4a16fb
    	return snd_sctl_install(h);
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    static int snd_pcm_hook_ctl_elems_hw_free(snd_pcm_hook_t *hook)
    Packit 4a16fb
    {
    Packit 4a16fb
    	snd_sctl_t *h = snd_pcm_hook_get_private(hook);
    Packit 4a16fb
    	return snd_sctl_remove(h);
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    static int snd_pcm_hook_ctl_elems_close(snd_pcm_hook_t *hook)
    Packit 4a16fb
    {
    Packit 4a16fb
    	snd_sctl_t *h = snd_pcm_hook_get_private(hook);
    Packit 4a16fb
    	int err = snd_sctl_free(h);
    Packit 4a16fb
    	snd_pcm_hook_set_private(hook, NULL);
    Packit 4a16fb
    	return err;
    Packit 4a16fb
    }
    Packit 4a16fb
    Packit 4a16fb
    /**
    Packit 4a16fb
     * \brief Install CTL settings using hardware associated with PCM handle
    Packit 4a16fb
     * \param pcm PCM handle
    Packit 4a16fb
     * \param conf Configuration node with CTL settings
    Packit 4a16fb
     * \return zero on success otherwise a negative error code
    Packit 4a16fb
     */
    Packit 4a16fb
    int _snd_pcm_hook_ctl_elems_install(snd_pcm_t *pcm, snd_config_t *conf)
    Packit 4a16fb
    {
    Packit 4a16fb
    	int err;
    Packit 4a16fb
    	int card;
    Packit 4a16fb
    	snd_pcm_info_t info = {0};
    Packit 4a16fb
    	char ctl_name[16];
    Packit 4a16fb
    	snd_ctl_t *ctl;
    Packit 4a16fb
    	snd_sctl_t *sctl = NULL;
    Packit 4a16fb
    	snd_config_t *pcm_conf = NULL;
    Packit 4a16fb
    	snd_pcm_hook_t *h_hw_params = NULL, *h_hw_free = NULL, *h_close = NULL;
    Packit 4a16fb
    	assert(conf);
    Packit 4a16fb
    	assert(snd_config_get_type(conf) == SND_CONFIG_TYPE_COMPOUND);
    Packit 4a16fb
    Packit 4a16fb
    	err = snd_pcm_info(pcm, &info;;
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	card = snd_pcm_info_get_card(&info;;
    Packit 4a16fb
    	if (card < 0) {
    Packit 4a16fb
    		SNDERR("No card for this PCM");
    Packit 4a16fb
    		return -EINVAL;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	sprintf(ctl_name, "hw:%d", card);
    Packit 4a16fb
    	err = snd_ctl_open(&ctl, ctl_name, 0);
    Packit 4a16fb
    	if (err < 0) {
    Packit 4a16fb
    		SNDERR("Cannot open CTL %s", ctl_name);
    Packit 4a16fb
    		return err;
    Packit 4a16fb
    	}
    Packit 4a16fb
    	err = snd_config_imake_pointer(&pcm_conf, "pcm_handle", pcm);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		goto _err;
    Packit 4a16fb
    	err = snd_sctl_build(&sctl, ctl, conf, pcm_conf, 0);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		goto _err;
    Packit 4a16fb
    	err = snd_pcm_hook_add(&h_hw_params, pcm, SND_PCM_HOOK_TYPE_HW_PARAMS,
    Packit 4a16fb
    			       snd_pcm_hook_ctl_elems_hw_params, sctl);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		goto _err;
    Packit 4a16fb
    	err = snd_pcm_hook_add(&h_hw_free, pcm, SND_PCM_HOOK_TYPE_HW_FREE,
    Packit 4a16fb
    			       snd_pcm_hook_ctl_elems_hw_free, sctl);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		goto _err;
    Packit 4a16fb
    	err = snd_pcm_hook_add(&h_close, pcm, SND_PCM_HOOK_TYPE_CLOSE,
    Packit 4a16fb
    			       snd_pcm_hook_ctl_elems_close, sctl);
    Packit 4a16fb
    	if (err < 0)
    Packit 4a16fb
    		goto _err;
    Packit 4a16fb
    	snd_config_delete(pcm_conf);
    Packit 4a16fb
    	return 0;
    Packit 4a16fb
     _err:
    Packit 4a16fb
    	if (h_hw_params)
    Packit 4a16fb
    		snd_pcm_hook_remove(h_hw_params);
    Packit 4a16fb
    	if (h_hw_free)
    Packit 4a16fb
    		snd_pcm_hook_remove(h_hw_free);
    Packit 4a16fb
    	if (h_close)
    Packit 4a16fb
    		snd_pcm_hook_remove(h_close);
    Packit 4a16fb
    	if (sctl)
    Packit 4a16fb
    		snd_sctl_free(sctl);
    Packit 4a16fb
    	if (pcm_conf)
    Packit 4a16fb
    		snd_config_delete(pcm_conf);
    Packit 4a16fb
    	return err;
    Packit 4a16fb
    }
    Packit 4a16fb
    #ifndef DOC_HIDDEN
    Packit 4a16fb
    SND_DLSYM_BUILD_VERSION(_snd_pcm_hook_ctl_elems_install, SND_PCM_DLSYM_VERSION);
    Packit 4a16fb
    #endif