All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Schmidt <stefan@datenfreihafen.org>
To: Stefan Schmidt <stefan@datenfreihafen.org>
Cc: alsa-devel@alsa-project.org,
	Mark Brown <broonie@opensource.wolfsonmicro.com>,
	Stefan Schmidt <stefan@slimlogic.co.uk>,
	Ian Molton <ian@mnementh.co.uk>,
	Graeme Gregory <gg@slimlogic.co.uk>,
	Liam Girdwood <lrg@slimlogic.co.uk>
Subject: Re: [PATCH] ascenario: Add scenario support to alsa-lib
Date: Thu, 1 Oct 2009 17:08:49 +0200	[thread overview]
Message-ID: <20091001150849.GE5936@excalibur.local> (raw)
In-Reply-To: <20091001131948.GA5936@excalibur.local>

Hello.

On Thu, 2009-10-01 at 15:19, Stefan Schmidt wrote:
> 
> On Thu, 2009-10-01 at 13:28, Mark Brown wrote:
> 
> > One thing I think I'm missing with the API documentation here is a
> > separation between the API used for setting up scenarios and the API
> > used by random client applications - it's there, but it could be
> > underlined a bit more.  Probably putting the client application stuff at
> > the top of the header file would help here since the functions that more
> > people will use will be visible first.
> 
> Sure can do this.

It now has the following order:
snd_scenario_list()
snd_scenario_set_scn()
snd_scenario_get_scn()
snd_scenario_get_master_playback_volume()
snd_scenario_get_master_playback_switch()
snd_scenario_get_master_capture_volume()
snd_scenario_get_master_capture_switch()
snd_scenario_set_qos()
snd_scenario_get_qos()
snd_scenario_open()
snd_scenario_reload()
snd_scenario_close()
snd_scenario_dump()

That should match what people are looking for: 1) what scenarios are available
2) get and set them 3) what else can I do? 4) boring setup stuff.

For an updated patch with all your comments inlcuded see below.


>From 57b01da743ccfc3a3baae55bd808d325bf58ce48 Mon Sep 17 00:00:00 2001
From: Stefan Schmidt <stefan@slimlogic.co.uk>
Date: Wed, 30 Sep 2009 16:22:45 +0200
Subject: [PATCH] ascenario: Add scenario support to alsa-lib

It allows switching audio settings between scenarios or uses-cases like
listening to music and answering an incoming phone call. Made of control
aliasing for playback, capture master and switch as well as the option to
post- and prefix a sequence of control changes avoiding pops and other
unwanted noise. Some example programs will be available in alsa-utils.

CC: Ian Molton <ian@mnementh.co.uk>
CC: Graeme Gregory <gg@slimlogic.co.uk>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Stefan Schmidt <stefan@slimlogic.co.uk>
---
 include/Makefile.am |    2 +-
 include/ascenario.h |  170 +++++++
 src/Makefile.am     |    2 +-
 src/ascenario.c     | 1358 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1530 insertions(+), 2 deletions(-)
 create mode 100644 include/ascenario.h
 create mode 100644 src/ascenario.c

diff --git a/include/Makefile.am b/include/Makefile.am
index a291503..572fbc9 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -3,7 +3,7 @@ SUBDIRS = sound
 sysincludedir = ${includedir}/sys
 alsaincludedir = ${includedir}/alsa
 
-alsainclude_HEADERS = asoundlib.h asoundef.h \
+alsainclude_HEADERS = asoundlib.h asoundef.h ascenario.h \
 		      version.h global.h input.h output.h error.h \
 		      conf.h control.h iatomic.h
 
diff --git a/include/ascenario.h b/include/ascenario.h
new file mode 100644
index 0000000..869f2ea
--- /dev/null
+++ b/include/ascenario.h
@@ -0,0 +1,170 @@
+/*
+*  ALSA Scenario header file
+*
+*   This library is free software; you can redistribute it and/or modify
+*   it under the terms of the GNU Lesser General Public License as
+*   published by the Free Software Foundation; either version 2.1 of
+*   the License, or (at your option) any later version.
+*
+*   This program is distributed in the hope that it will be useful,
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*   GNU Lesser General Public License for more details.
+*
+*   You should have received a copy of the GNU Lesser General Public
+*   License along with this library; if not, write to the Free Software
+*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+*
+*  Copyright (C) 2008-2009 SlimLogic Ltd
+*  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+*           Stefan Schmidt <stefan@slimlogic.co.uk>
+*/
+
+/**
+ * Scenario IDs
+ *
+ * Standard Scenario IDs - Add new scenarios at the end.
+ */
+
+#define SND_SCN_PLAYBACK_SPEAKER        "playback speaker"
+#define SND_SCN_PLAYBACK_HEADPHONES     "playback headphone"
+#define SND_SCN_PLAYBACK_HEADSET        "playback headset"
+#define SND_SCN_PLAYBACK_BLUETOOTH      "playback bluetooth"
+#define SND_SCN_PLAYBACK_HANDSET        "playback handset"
+#define SND_SCN_PLAYBACK_GSM            "playback gsm"
+#define SND_SCN_PLAYBACK_LINE           "playback line"
+
+#define SND_SCN_CAPTURE_MIC             "capture mic"
+#define SND_SCN_CAPTURE_LINE            "capture line"
+#define SND_SCN_CAPTURE_HEADSET         "capture headset"
+#define SND_SCN_CAPTURE_HANDSET         "capture handset"
+#define SND_SCN_CAPTURE_BLUETOOTH       "capture bluetooth"
+#define SND_SCN_CAPTURE_GSM             "capture gsm"
+
+#define SND_SCN_PHONECALL_GSM_HANDSET   "phonecall gsm handset"
+#define SND_SCN_PHONECALL_BT_HANDSET    "phonecall bt handset"
+#define SND_SCN_PHONECALL_IP_HANDSET    "phonecall ip handset"
+#define SND_SCN_PHONECALL_GSM_HEADSET   "phonecall gsm headset"
+#define SND_SCN_PHONECALL_BT_HEADSET    "phonecall bt headset"
+#define SND_SCN_PHONECALL_IP_HEADSET    "phonecall ip headset"
+
+/**
+ * QOS
+ *
+ * Defines Audio Quality of Service. Systems supporting different types of QoS
+ * often have lower power consumption on lower quality levels.
+ */
+#define SND_POWER_QOS_HIFI			0
+#define SND_POWER_QOS_VOICE			1
+#define SND_POWER_QOS_SYSTEM			2
+
+struct snd_scenario;
+
+/* TODO: add notification */
+
+/**
+ * snd_scenario_list - list supported scenarios
+ * @scn: scenario
+ * @list: list of supported scenario names.
+ *
+ * List supported scenarios for this sound card.
+ * Returns number of scenarios.
+ */
+int snd_scenario_list(struct snd_scenario *scn, const char **list[]);
+
+/**
+ * snd_scenario_set_scn - set scenario
+ * @scn: scenario
+ * @scenario: scenario name
+ *
+ * Set new scenario for sound card.
+ */
+int snd_scenario_set_scn(struct snd_scenario *scn, const char *scenario);
+
+/**
+ * snd_scenario_get_scn - get scenario
+ * @scn: scenario
+ *
+ * Get current sound card scenario.
+ */
+const char *snd_scenario_get_scn(struct snd_scenario *scn);
+
+/**
+ * snd_scenario_get_master_playback_volume - get playback volume
+ * @scn: scenario
+ *
+ * Get the master playback volume control name for the current scenario.
+ */
+int snd_scenario_get_master_playback_volume(struct snd_scenario *scn);
+
+/**
+ * snd_scenario_get_master_playback_switch - get playback switch
+ * @scn: scenario
+ *
+ * Get the master playback switch control name for the current scenario.
+ */
+ int snd_scenario_get_master_playback_switch(struct snd_scenario *scn);
+
+/**
+ * snd_scenario_get_master_capture_volume - get capture volume
+ * @scn: scenario
+ *
+ * Get the master capture volume control name for the current scenario.
+ */
+int snd_scenario_get_master_capture_volume(struct snd_scenario *scn);
+
+/**
+ * snd_scenario_get_master_capture_switch - get capture switch
+ * @scn: scenario
+ *
+ * Get the master capture switch control name for the current scenario.
+ */
+int snd_scenario_get_master_capture_switch(struct snd_scenario *scn);
+
+/**
+ * snd_scenario_set_qos - set qos
+ * @qos: qos
+ *
+ * Set Quality of Service for this scenario.
+ */
+int snd_scenario_set_qos(struct snd_scenario *scn, int qos);
+
+/**
+ * snd_scenario_get_qos - get qos
+ * @scn: scenario
+ *
+ * Get Quality of Service for this scenario.
+ */
+int snd_scenario_get_qos(struct snd_scenario *scn);
+
+/**
+ * snd_scenario_open - open scenario core
+ * @card_name: sound card name.
+ *
+ * Open scenario manager core for sound card.
+ */
+struct snd_scenario *snd_scenario_open(const char *card_name);
+
+/**
+ * snd_scenario_reload - reload and reparse scenario configuration
+ * @scn: scenario
+ *
+ * Reloads and reparses sound card scenario configuration.
+ */
+int snd_scenario_reload(struct snd_scenario *scn);
+
+/**
+ * snd_scenario_close - close scenario core
+ * @scn: scenario
+ *
+ * Free scenario manager core for sound card.
+ */
+void snd_scenario_close(struct snd_scenario *scn);
+
+/**
+ * snd_scenario_dump - dump
+ * @card_name: sound card name.
+ *
+ * Dump current sound card settings to stdout in scn format.
+ */
+int snd_scenario_dump(const char *card_name);
diff --git a/src/Makefile.am b/src/Makefile.am
index 3204fe4..be46cb3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,7 +14,7 @@ SYMFUNCS =
 endif
 
 lib_LTLIBRARIES = libasound.la
-libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c userfile.c names.c
+libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c userfile.c names.c ascenario.c
 
 SUBDIRS=control
 libasound_la_LIBADD = control/libcontrol.la
diff --git a/src/ascenario.c b/src/ascenario.c
new file mode 100644
index 0000000..74082d4
--- /dev/null
+++ b/src/ascenario.c
@@ -0,0 +1,1358 @@
+/*
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *  Copyright (C) 2008-2009 SlimLogic Ltd
+ *  Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *	     Stefan Schmidt <stefan@slimlogic.co.uk>
+ */
+
+#define _GNU_SOURCE /* needed of O_NOATIME */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <alsa/asoundlib.h>
+
+#include "../include/ascenario.h"
+
+#define PRE_SEQ		0
+#define POST_SEQ	1
+#define MAX_SCN		32
+#define MAX_NAME	64
+#define MAX_FILE	256
+#define MAX_BUF		256
+#define ALSA_SCN_DIR	"/etc/alsa/scenario"
+
+/*
+ * Stores all scenario settings for 1 kcontrol. Hence we have a
+ * control_settings for each kcontrol in card.
+ */
+struct control_settings {
+	char name[MAX_NAME];
+	int id;
+	snd_ctl_elem_type_t type;
+	int count; /* 1 = mono, 2 = stereo, etc */
+	unsigned short *value; /* kcontrol value 2D array */
+};
+
+/*
+ * If sleep is 0 the element contains the settings in control. Else sleep
+ * contains the sleep time in micro seconds.
+ */
+struct sequence_element {
+	unsigned int sleep; /* Sleep time in msecs if sleep element, else 0 */
+	struct control_settings *control;
+	struct sequence_element *next; /* Pointer to next list element */
+};
+
+/*
+ * Describes default mixers and qos for scenario.
+ * We have a scenario_info for each scenario loaded.
+ */
+struct scenario_info {
+	char *name;
+	char *file;
+	char *pre_sequence_file;
+	char *post_sequence_file;
+	short playback_volume_id;
+	short playback_switch_id;
+	short capture_volume_id;
+	short capture_switch_id;
+	int qos;
+};
+
+/* Describe a snd card and all its scenarios.
+ */
+struct snd_scenario {
+	char *card_name;
+	int current_scenario;
+	int num_scenarios; /* number of supported scenarios */
+	int num_kcontrols;  /* number of kcontrols */
+	struct sequence_element *pre_seq_list; /* Linked list for pre sequence */
+	struct sequence_element *post_seq_list; /* Linked list for post sequence */
+	const char **list;
+	struct scenario_info *scenario; /* var len array of scenario info */
+	struct control_settings *control; /* var len array of controls */
+};
+
+static void scn_error(const char *fmt,...)
+{
+	va_list va;
+	va_start(va, fmt);
+	fprintf(stderr, "scenario: ");
+	vfprintf(stderr, fmt, va);
+	va_end(va);
+}
+
+static void scn_stdout(const char *fmt,...)
+{
+	va_list va;
+	va_start(va, fmt);
+	vfprintf(stdout, fmt, va);
+	va_end(va);
+}
+
+static inline void set_value(struct snd_scenario *scn,
+	struct control_settings *control, int count, unsigned short val)
+{
+	int offset = scn->current_scenario * control->count;
+	control->value[offset + count] = val;
+}
+
+static inline unsigned short get_value(struct snd_scenario *scn,
+	struct control_settings *control, int count)
+{
+	int offset = scn->current_scenario * control->count;
+	return control->value[offset + count];
+}
+
+static int dump_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id)
+{
+	int err, count, i;
+	snd_ctl_elem_info_t *info;
+	snd_ctl_elem_type_t type;
+	snd_ctl_elem_value_t *control;
+
+	snd_ctl_elem_info_alloca(&info);
+	snd_ctl_elem_value_alloca(&control);
+
+	snd_ctl_elem_info_set_id(info, id);
+	err = snd_ctl_elem_info(handle, info);
+	if (err < 0) {
+		scn_stdout("%s: failed to get ctl info\n");
+		return err;
+	}
+
+	snd_ctl_elem_value_set_id(control, id);
+	snd_ctl_elem_read(handle, control);
+
+	type = snd_ctl_elem_info_get_type(info);
+	count = snd_ctl_elem_info_get_count(info);
+	if (count == 0)
+		return 0;
+
+	scn_stdout("%u:'%s':%d:",
+	       snd_ctl_elem_id_get_numid(id),
+	       snd_ctl_elem_id_get_name(id), count);
+
+	switch (type) {
+	case SND_CTL_ELEM_TYPE_BOOLEAN:
+		for (i = 0; i < count - 1; i++)
+			scn_stdout("%d,",
+				snd_ctl_elem_value_get_boolean(control, i));
+		scn_stdout("%d", snd_ctl_elem_value_get_boolean(control, i));
+		break;
+	case SND_CTL_ELEM_TYPE_INTEGER:
+		for (i = 0; i < count - 1; i++)
+			scn_stdout("%d,",
+				snd_ctl_elem_value_get_integer(control, i));
+		scn_stdout("%d", snd_ctl_elem_value_get_integer(control, i));
+		break;
+	case SND_CTL_ELEM_TYPE_INTEGER64:
+		for (i = 0; i < count - 1; i++)
+			scn_stdout("%ld,",
+				snd_ctl_elem_value_get_integer64(control, i));
+		scn_stdout("%ld",
+				snd_ctl_elem_value_get_integer64(control, i));
+		break;
+	case SND_CTL_ELEM_TYPE_ENUMERATED:
+		for (i = 0; i < count - 1; i++)
+			scn_stdout("%d,",
+				snd_ctl_elem_value_get_enumerated(control, i));
+		scn_stdout("%d",
+				snd_ctl_elem_value_get_enumerated(control, i));
+		break;
+	case SND_CTL_ELEM_TYPE_BYTES:
+		for (i = 0; i < count - 1; i++)
+			scn_stdout("%2.2x,",
+				snd_ctl_elem_value_get_byte(control, i));
+		scn_stdout("%2.2x", snd_ctl_elem_value_get_byte(control, i));
+		break;
+	default:
+		break;
+	}
+	scn_stdout("\n");
+	return 0;
+}
+
+/*
+ * Add new kcontrol from sound card into memory database.
+ */
+static int add_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id,
+	struct control_settings *control_settings)
+{
+	int err;
+	snd_ctl_elem_info_t *info;
+	snd_ctl_elem_value_t *control;
+
+	snd_ctl_elem_info_alloca(&info);
+	snd_ctl_elem_value_alloca(&control);
+
+	snd_ctl_elem_info_set_id(info, id);
+	err = snd_ctl_elem_info(handle, info);
+	if (err < 0) {
+		scn_stdout("%s: failed to get ctl info\n");
+		return err;
+	}
+
+	snd_ctl_elem_value_set_id(control, id);
+	snd_ctl_elem_read(handle, control);
+
+	strncpy(control_settings->name, snd_ctl_elem_id_get_name(id),
+		MAX_NAME);
+	control_settings->count = snd_ctl_elem_info_get_count(info);
+	control_settings->type = snd_ctl_elem_info_get_type(info);
+	control_settings->id = snd_ctl_elem_id_get_numid(id);
+	return 0;
+}
+
+static int parse_controls(struct snd_scenario *scn, FILE *f)
+{
+	struct control_settings *control;
+	char buf[MAX_BUF], name[MAX_NAME];
+	int id, count, line = 1, i;
+	char *name_start, *name_end, *tbuf;
+
+	while (fgets(buf, MAX_BUF, f) != NULL) {
+
+		/* get id */
+		tbuf = buf;
+		id = atoi(tbuf);
+		if (id == 0) {
+			scn_error("%s:id == 0 on line %d\n", __func__, line);
+			return -EINVAL;
+		}
+		for (i = 0; i < scn->num_kcontrols; i++) {
+			if (id == scn->control[i].id) {
+				control = &scn->control[i];
+				goto get_name;
+			}
+		}
+		scn_error("%s:id not found at line %d\n", __func__, line);
+			return -EINVAL;
+get_name:
+		/* get name start */
+		while (*tbuf != 0 && *tbuf != '\'')
+			tbuf++;
+		if (*tbuf == 0)
+			return -EINVAL;
+		name_start = ++tbuf;
+
+		/* get name end */
+		while (*tbuf != 0 && *tbuf != '\'')
+			tbuf++;
+		if (*tbuf == 0)
+			return -EINVAL;
+		name_end = tbuf++;
+
+		/* copy name */
+		if ((name_end - name_start) > MAX_NAME) {
+			scn_error("%s:name too big at %d chars line %d\n",
+				 __func__, name_end - name_start, line);
+			return -EINVAL;
+		}
+		strncpy(name, name_start, name_end - name_start);
+		name[name_end - name_start] = 0;
+		if (strcmp(name, control->name)) {
+			scn_error("%s: name %s and %s don't match at line %d\n",
+				 __func__, name, control->name, line);
+			return -EINVAL;
+		}
+
+		/* get count */
+		tbuf++;
+		count = atoi(tbuf);
+		if (count == 0) {
+			scn_error("%s:count == 0 on line %d\n", __func__,
+				line);
+			return -EINVAL;
+		}
+		if (count != control->count) {
+			scn_error("%s:count does not match at line %d\n",
+				__func__, line);
+			return -EINVAL;
+		}
+
+		/* get vals */
+		control->value = malloc(control->count * scn->num_scenarios *
+			sizeof(unsigned short));
+		if (control->value == NULL)
+			return -ENOMEM;
+
+		while (*tbuf != 0 && *tbuf != ':')
+			tbuf++;
+		if (*tbuf == 0)
+			return -EINVAL;
+		tbuf++;
+
+		for (i = 0; i < count; i++) {
+			set_value(scn, control, i, atoi(tbuf));
+			while (*tbuf != 0 && *tbuf != ',')
+				tbuf++;
+
+			if (*tbuf++ == 0 && i < (count - 1))
+				return -EINVAL;
+		}
+		line++;
+	}
+
+	return 0;
+}
+
+static char *get_string (char *buf)
+{
+	char *str, *end;
+
+	/* find '=' */
+	while (isblank(*buf))
+		buf++;
+	if (*buf == 0 || *buf != '=') {
+		scn_error("%s: missing '='\n", __func__);
+		return NULL;
+	}
+
+	/* find leading '"' */
+	buf++;
+	while (isblank(*buf))
+		buf++;
+	if (*buf == 0 || *buf != '"') {
+		scn_error("%s: missing start '\"'\n", __func__);
+		return NULL;
+	}
+	str = ++buf;
+
+	/* get value */
+	while (*buf != 0 && *buf != '"')
+		buf++;
+	end = buf;
+
+	/* find '"' terminator */
+	if (*buf == 0 || *buf != '"') {
+		scn_error("%s: missing terminator '\"' %s\n", __func__, buf);
+		return NULL;
+	}
+
+	*end = 0;
+	return strdup(str);
+}
+
+static char *get_control_name (char *buf)
+{
+	char *str, *end;
+
+	/* find leading '"' */
+	buf++;
+	while (isblank(*buf))
+		buf++;
+	if (*buf == 0 || *buf != '"') {
+		scn_error("%s: missing start '\"'\n", __func__);
+		return NULL;
+	}
+	str = ++buf;
+
+	/* get value */
+	while (*buf != 0 && *buf != '"')
+		buf++;
+	end = buf;
+
+	/* find '"' terminator */
+	if (*buf == 0 || *buf != '"') {
+		scn_error("%s: missing terminator '\"' %s\n", __func__, buf);
+		return NULL;
+	}
+
+	*end = 0;
+	return strdup(str);
+}
+
+static int get_int (char *buf)
+{
+	/* find '=' */
+	while (isblank(*buf))
+		buf++;
+	if (*buf == 0 || *buf != '=') {
+		scn_error("%s: missing '='\n", __func__);
+		return -EINVAL;
+	}
+	buf++;
+	return atoi(buf);
+}
+
+static int get_enum (char *buf)
+{
+	/* find '=' */
+	while (isblank(*buf))
+		buf++;
+	if (*buf == 0 || *buf != '=') {
+		scn_error("%s: missing '='\n", __func__);
+		return -EINVAL;
+	}
+	buf++;
+	return 0; /* TODO */
+}
+
+static void seq_list_append(struct snd_scenario *scn,
+			struct sequence_element *curr, int position)
+{
+	struct sequence_element *last, *tmp;
+
+	if (position) {
+		if (!scn->post_seq_list)
+			scn->post_seq_list = curr;
+
+		else {
+			tmp = scn->post_seq_list;
+			while (tmp) {
+				last = tmp;
+				tmp = tmp->next;
+			}
+			last->next = curr;
+		}
+	}
+	else {
+		if (!scn->pre_seq_list) {
+			scn->pre_seq_list = curr;
+		}
+		else {
+			tmp = scn->pre_seq_list;
+			while (tmp) {
+				last = tmp;
+				tmp = tmp->next;
+			}
+			last->next = curr;
+		}
+	}
+}
+
+static int parse_sequences(struct snd_scenario *scn, FILE *f, int position)
+{
+	char buf[MAX_BUF], *tbuf, *control_value;
+	int control_len, i;
+	struct sequence_element *curr;
+
+	while (fgets(buf, MAX_BUF, f) != NULL) {
+
+		/* Check for lines with comments and ignore */
+		if (buf[0] == '#')
+			continue;
+
+		/* Parse current line and skip blanks */
+		tbuf = buf;
+		while (isblank(*tbuf))
+			tbuf++;
+
+		curr = malloc(sizeof(struct sequence_element));
+		if (curr == NULL)
+			return -ENOMEM;
+		bzero(curr, sizeof(struct sequence_element));
+
+		curr->control = malloc(sizeof(struct control_settings));
+		if (curr->control == NULL)
+			return -ENOMEM;
+		bzero(curr->control, sizeof(struct control_settings));
+
+		curr->control->value = malloc(curr->control->count * scn->num_scenarios
+						* sizeof(unsigned short));
+		if (curr->control->value == NULL)
+			return -ENOMEM;
+		bzero(curr->control->value, curr->control->count * scn->num_scenarios
+				* sizeof(unsigned short));
+
+		if (strncmp(tbuf, "kcontrol", 8) == 0) {
+			strncpy(curr->control->name, get_control_name(tbuf + 8), MAX_NAME);
+			control_len = strlen(curr->control->name);
+			/* 11 = 8 from kcontrol + 2 quotes + 1 blank */
+			control_value = get_string(tbuf + 11 + control_len);
+
+			for (i = 0; i < scn->num_kcontrols; i++) {
+				if (strncmp(curr->control->name, scn->control[i].name,
+						control_len) == 0) {
+					curr->sleep = 0;
+					curr->control->id = scn->control[i].id;
+					curr->control->type = scn->control[i].type;
+					curr->control->count = scn->control[i].count;
+					set_value(scn, curr->control, curr->control->count,
+							atoi(control_value));
+					seq_list_append(scn, curr, position);
+				}
+			}
+
+			continue;
+		}
+
+		if (strncmp(tbuf, "msleep", 6) == 0) {
+			curr->sleep = get_int(tbuf + 6);
+
+			/* Free control elements as we only have a sleep element
+			 * here */
+			if (curr->control) {
+				if (curr->control->value)
+					free(curr->control->value);
+				free(curr->control);
+			}
+
+			seq_list_append(scn, curr, position);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+/* load scenario i */
+static int read_scenario_file(struct snd_scenario *scn)
+{
+	int fd, ret;
+	FILE *f;
+	char filename[MAX_FILE];
+	struct scenario_info *info = &scn->scenario[scn->current_scenario];
+
+	snprintf(filename, MAX_FILE, "%s/%s/%s", ALSA_SCN_DIR, scn->card_name,
+		info->file);
+
+	fd = open(filename, O_RDONLY | O_NOATIME);
+	if (fd < 0) {
+		scn_error("%s: couldn't open %s\n", __func__, filename);
+		return fd;
+	}
+
+	f = fdopen(fd, "r");
+	if (f == NULL) {
+		ret = errno;
+		goto close;
+	}
+
+	ret = parse_controls(scn, f);
+	fclose(f);
+close:
+	close(fd);
+	return ret;
+}
+
+static int read_sequence_file(struct snd_scenario *scn, int position)
+{
+	int fd, ret;
+	FILE *f;
+	char filename[MAX_FILE];
+	struct scenario_info *info = &scn->scenario[scn->current_scenario];
+
+	if (position == PRE_SEQ) {
+		sprintf(filename, "%s/%s/%s", ALSA_SCN_DIR, scn->card_name,
+			info->pre_sequence_file);
+	}
+	else {
+		sprintf(filename, "%s/%s/%s", ALSA_SCN_DIR, scn->card_name,
+			info->post_sequence_file);
+	}
+
+	fd = open(filename, O_RDONLY | O_NOATIME);
+	if (fd < 0) {
+		return fd;
+	}
+
+	f = fdopen(fd, "r");
+	if (f == NULL) {
+		ret = errno;
+		goto close;
+	}
+
+	ret = parse_sequences(scn, f, position);
+	fclose(f);
+close:
+	close(fd);
+	return ret;
+}
+
+static int parse_scenario(struct snd_scenario *scn, FILE *f, int line_)
+{
+	struct scenario_info *info;
+	int line = line_ - 1, id = 0, file = 0;
+	char buf[MAX_BUF], *tbuf;
+
+	scn->scenario = realloc(scn->scenario,
+		(scn->num_scenarios + 1) * sizeof(struct scenario_info));
+	if (scn->scenario == NULL)
+		return -ENOMEM;
+	bzero(scn->scenario, sizeof(struct scenario_info));
+	info = scn->scenario + scn->num_scenarios;
+
+	/* Set sequence filename to NULL as it is optional and we want to check
+	 * for  NULL to avoid segfaults */
+	info->pre_sequence_file = NULL;
+	info->post_sequence_file = NULL;
+
+	while(fgets(buf, MAX_BUF, f) != NULL) {
+
+		line++;
+		if (buf[0] == '#')
+			continue;
+
+		tbuf = buf;
+		while (isblank(*tbuf))
+			tbuf++;
+
+		if (strncmp(tbuf, "Identifier", 10) == 0) {
+			info->name = get_string(tbuf + 10);
+			if (info->name == NULL) {
+				scn_error("%s: failed to get Identifer\n",
+					__func__);
+				goto err;
+			}
+			id = 1;
+			continue;
+		}
+
+		if (strncmp(tbuf, "File", 4) == 0) {
+			info->file = get_string(tbuf + 4);
+			if (info->file == NULL) {
+				scn_error("%s: failed to get File\n",
+					__func__);
+				goto err;
+			}
+			file = 1;
+			continue;
+		}
+
+		if (strncmp(tbuf, "QoS", 3) == 0) {
+			info->qos = get_enum(tbuf + 3);
+			if (info->qos < 0) {
+				scn_error("%s: failed to get QoS\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "MasterPlaybackVolume", 20) == 0) {
+			info->playback_volume_id = get_int(tbuf + 20);
+			if (info->playback_volume_id < 0) {
+				scn_error("%s: failed to get MasterPlaybackVolume\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "MasterPlaybackSwitch", 20) == 0) {
+			info->playback_switch_id = get_int(tbuf + 20);
+			if (info->playback_switch_id < 0) {
+				scn_error("%s: failed to get MasterPlaybackSwitch\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "MasterCaptureVolume", 19) == 0) {
+			info->capture_volume_id = get_int(tbuf + 19);
+			if (info->capture_volume_id < 0) {
+				scn_error("%s: failed to get MasterCaptureVolume\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "MasterCaptureSwitch", 19) == 0) {
+			info->capture_switch_id = get_int(tbuf + 19);
+			if (info->capture_switch_id < 0) {
+				scn_error("%s: failed to get MasterCaptureSwitch\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "PreSequenceFile", 15) == 0) {
+			info->pre_sequence_file = get_string(tbuf + 15);
+			if (info->pre_sequence_file == NULL) {
+				scn_error("%s: failed to get PreSequenceFile\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "PostSequenceFile", 16) == 0) {
+			info->post_sequence_file = get_string(tbuf + 16);
+			if (info->post_sequence_file == NULL) {
+				scn_error("%s: failed to get PostSequenceFile\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "EndSection", 10) == 0) {
+			break;
+		}
+	}
+
+	if (file & id) {
+		scn->num_scenarios++;
+		return 0;
+	}
+err:
+	if (file) {
+		free(info->file);
+		info->file = NULL;
+	}
+	if (id) {
+		free(info->name);
+		info->name = NULL;
+	}
+	return -EINVAL;
+}
+
+static int read_master_file(struct snd_scenario *scn, FILE *f)
+{
+	int line = 0, ret = 0, i;
+	char buf[MAX_BUF], *tbuf;
+
+	/* parse master config sections */
+	while(fgets(buf, MAX_BUF, f) != NULL) {
+
+		if (buf[0] == '#') {
+			line++;
+			continue;
+		}
+
+		if (strncmp(buf, "Section", 7) == 0) {
+
+			tbuf = buf + 7;
+			while (isblank(*tbuf))
+				tbuf++;
+
+			if (strncmp(tbuf, "\"Scenario\"", 10) == 0) {
+				line = parse_scenario(scn, f, line);
+				if (line < 0) {
+					scn_error("%s: failed to parse "
+						"scenario\n", __func__);
+					goto err;
+				}
+				continue;
+			}
+		}
+		line++;
+	}
+
+	/* copy ptrs to scenario names */
+	scn->list = malloc(scn->num_scenarios * sizeof(char *));
+	if (scn->list == NULL)
+		ret = -ENOMEM;
+	for (i = 0; i < scn->num_scenarios; i++)
+		scn->list[i] = scn->scenario[i].name;
+
+err:
+	if (ferror(f)) {
+		scn_error("%s: failed to read master\n", __func__);
+		return ferror(f);
+	}
+	return ret;
+}
+
+/* load scenario i */
+static int import_master_config(struct snd_scenario *scn)
+{
+	int fd, ret;
+	FILE *f;
+	char filename[MAX_FILE];
+
+	sprintf(filename, "%s/%s.conf", ALSA_SCN_DIR, scn->card_name);
+
+	fd = open(filename, O_RDONLY | O_NOATIME);
+	if (fd < 0) {
+		scn_error("%s: couldn't open %s\n", __func__, filename);
+		return fd;
+	}
+
+	f = fdopen(fd, "r");
+	if (f == NULL) {
+		ret = errno;
+		goto close;
+	}
+
+	ret = read_master_file(scn, f);
+	fclose(f);
+close:
+	close(fd);
+	return ret;
+}
+
+/* parse_card_controls
+ * @scn: scenario
+ *
+ * Parse sound card and store control data in memory db.
+ */
+static int parse_card_controls(struct snd_scenario *scn)
+{
+	struct control_settings *control;
+	snd_ctl_t *handle;
+	snd_ctl_card_info_t *info;
+	snd_ctl_elem_list_t *list;
+	int ret, i;
+
+	snd_ctl_card_info_alloca(&info);
+	snd_ctl_elem_list_alloca(&list);
+
+	/* open and load snd card */
+	ret = snd_ctl_open(&handle, scn->card_name, SND_CTL_READONLY);
+	if (ret < 0) {
+		scn_error("%s: control %s open retor: %s\n", __func__,
+			scn->card_name, snd_strerror(ret));
+		return ret;
+	}
+
+	ret = snd_ctl_card_info(handle, info);
+	if (ret < 0) {
+		scn_error("%s :control %s local retor: %s\n", __func__,
+			scn->card_name, snd_strerror(ret));
+		goto close;
+	}
+
+	ret = snd_ctl_elem_list(handle, list);
+	if (ret < 0) {
+		scn_error("%s: cannot determine controls: %s\n", __func__,
+			snd_strerror(ret));
+		goto close;
+	}
+
+	scn->num_kcontrols = snd_ctl_elem_list_get_count(list);
+	if (scn->num_kcontrols < 0) {
+		ret = 0;
+		goto close;
+	}
+
+	snd_ctl_elem_list_set_offset(list, 0);
+	if (snd_ctl_elem_list_alloc_space(list, scn->num_kcontrols) < 0) {
+		scn_error("%s: not enough memory...\n", __func__);
+		ret =  -ENOMEM;
+		goto close;
+	}
+	if ((ret = snd_ctl_elem_list(handle, list)) < 0) {
+		scn_error("%s: cannot determine controls: %s\n", __func__,
+			snd_strerror(ret));
+		goto free;
+	}
+
+	/* allocate db memory for controls */
+	scn->control = calloc(scn->num_kcontrols,
+		sizeof(struct control_settings));
+	if (scn->control == NULL) {
+		ret = -ENOMEM;
+		goto free;
+	}
+	control = scn->control;
+
+	/* iterate through each kcontrol and add to db */
+	for (i = 0; i < scn->num_kcontrols; ++i) {
+		snd_ctl_elem_id_t *id;
+		snd_ctl_elem_id_alloca(&id);
+		snd_ctl_elem_list_get_id(list, i, id);
+
+		ret = add_control(handle, id, control++);
+		if (ret < 0) {
+			scn_error("%s: failed to add control error %s\n",
+				__func__, snd_strerror(ret));
+			goto close;
+		}
+	}
+free:
+	snd_ctl_elem_list_free_space(list);
+close:
+	snd_ctl_close(handle);
+	return ret;
+}
+
+/* import_scenario_files -
+ * @scn: scenario
+ *
+ * Read and parse scenario_info files the store in memory.
+ */
+static int import_scenario_files(struct snd_scenario *scn)
+{
+	int ret;
+
+	ret = import_master_config(scn);
+	if (ret < 0) {
+		scn_error("%s: failed to parse master scenario config\n",
+			__func__);
+		return ret;
+	}
+
+	for (scn->current_scenario = 0;
+		scn->current_scenario < scn->num_scenarios;
+		scn->current_scenario++) {
+
+		ret = read_scenario_file(scn);
+		if (ret < 0) {
+			scn_error("%s: failed to parse scenario %s\n",
+				__func__,
+				scn->scenario[scn->current_scenario].name);
+				scn->current_scenario = -1;
+			return ret;
+		}
+
+		if (scn->scenario[scn->current_scenario].pre_sequence_file != NULL) {
+			ret = read_sequence_file(scn, PRE_SEQ);
+			if (ret < 0) {
+				scn_stdout("Warning: PreSequence file defined but"
+					" missing in scenario \"%s\"\n",
+					scn->scenario[scn->current_scenario].name);
+			}
+		}
+
+		if (scn->scenario[scn->current_scenario].post_sequence_file != NULL) {
+			ret = read_sequence_file(scn, POST_SEQ);
+			if (ret < 0) {
+				scn_stdout("Warning: PostSequence file defined but"
+					" missing in scenario \"%s\"\n",
+					scn->scenario[scn->current_scenario].name);
+			}
+		}
+
+	}
+	return 0;
+}
+
+/* free all resorces */
+static void free_scn(struct snd_scenario *scn)
+{
+	/* TODO: valgrind to make sure. */
+	int i;
+
+	if (scn == NULL)
+		return;
+
+	if (scn->control) {
+		if (scn->control->value)
+			free(scn->control->value);
+		free(scn->control);
+	}
+
+	if (scn->list)
+		free(scn->list);
+	if (scn->card_name)
+		free(scn->card_name);
+	if (scn->pre_seq_list)
+		free(scn->pre_seq_list);
+	if (scn->post_seq_list)
+		free(scn->post_seq_list);
+
+	if (scn->scenario) {
+		for (i = 0; i < scn->num_scenarios; i++) {
+			struct scenario_info *info = &scn->scenario[i];
+
+			if (info->name)
+				free(info->name);
+			if (info->file)
+				free(info->file);
+			if (info->pre_sequence_file)
+				free(info->pre_sequence_file);
+			if (info->post_sequence_file)
+				free(info->post_sequence_file);
+		}
+		free(scn->scenario);
+	}
+	free(scn);
+}
+
+/*
+ * Init sound card scenario db.
+ */
+struct snd_scenario *snd_scenario_open(const char *card_name)
+{
+	struct snd_scenario *scn;
+	int err;
+
+	/* TODO: locking and
+	 * check if card_name scn is already loaded,
+	 * if so reuse to conserve ram. */
+
+	scn = malloc(sizeof(struct snd_scenario));
+	if (scn == NULL)
+		return NULL;
+	bzero(scn, sizeof(struct snd_scenario));
+	scn->card_name = strdup(card_name);
+	if (scn->card_name == NULL) {
+		free(scn);
+		return NULL;
+	}
+
+	/* get info about sound card */
+	err = parse_card_controls(scn);
+	if (err < 0) {
+		free_scn(scn);
+		return NULL;
+	}
+
+	/* get info on scenarios and verify against card */
+	err = import_scenario_files(scn);
+	if (err < 0) {
+		free_scn(scn);
+		return NULL;
+	}
+
+	return scn;
+}
+
+/*
+ * Reload and reparse scenario db.
+ */
+int snd_scenario_reload(struct snd_scenario *scn)
+{
+	free_scn(scn);
+
+	scn->num_kcontrols = parse_card_controls(scn);
+	if (scn->num_kcontrols <= 0) {
+		free_scn(scn);
+		return -EINVAL;
+	}
+
+	scn->num_scenarios = import_scenario_files(scn);
+	if (scn->num_scenarios <= 0) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void snd_scenario_close(struct snd_scenario *scn)
+{
+	free_scn(scn);
+}
+
+static int set_control(snd_ctl_t *handle, snd_ctl_elem_id_t *id,
+	struct snd_scenario *scn)
+{
+	struct control_settings *setting;
+	int ret, count, i, idnum;
+	snd_ctl_elem_info_t *info;
+	snd_ctl_elem_type_t type;
+	snd_ctl_elem_value_t *control;
+
+	snd_ctl_elem_info_alloca(&info);
+	snd_ctl_elem_value_alloca(&control);
+
+	snd_ctl_elem_info_set_id(info, id);
+	ret = snd_ctl_elem_info(handle, info);
+	if (ret < 0) {
+		scn_error("%s: failed to get ctl info\n", __func__);
+		return ret;
+	}
+
+	snd_ctl_elem_value_set_id(control, id);
+	snd_ctl_elem_read(handle, control);
+
+	idnum = snd_ctl_elem_id_get_numid(id);
+	for (i = 0; i < scn->num_kcontrols; i++) {
+		setting = &scn->control[i];
+		if (setting->id == idnum)
+			goto set_val;
+	}
+	scn_error("%s: failed to find control %d\n", __func__, idnum);
+	return 0;
+
+set_val:
+	type = snd_ctl_elem_info_get_type(info);
+	count = snd_ctl_elem_info_get_count(info);
+	if (count == 0)
+		return 0;
+
+	switch (type) {
+	case SND_CTL_ELEM_TYPE_BOOLEAN:
+		for (i = 0; i < count; i++)
+			snd_ctl_elem_value_set_boolean(control, i,
+				get_value(scn, setting, i));
+		break;
+	case SND_CTL_ELEM_TYPE_INTEGER:
+		for (i = 0; i < count; i++)
+			snd_ctl_elem_value_set_integer(control, i,
+				get_value(scn, setting, i));
+
+		break;
+	case SND_CTL_ELEM_TYPE_INTEGER64:
+		for (i = 0; i < count; i++)
+			snd_ctl_elem_value_set_integer64(control, i,
+				get_value(scn, setting, i));
+
+		break;
+	case SND_CTL_ELEM_TYPE_ENUMERATED:
+		for (i = 0; i < count; i++)
+			snd_ctl_elem_value_set_enumerated(control, i,
+				get_value(scn, setting, i));
+
+		break;
+	case SND_CTL_ELEM_TYPE_BYTES:
+		for (i = 0; i < count; i++)
+			snd_ctl_elem_value_set_byte(control, i,
+				get_value(scn, setting, i));
+		break;
+	default:
+		break;
+	}
+
+	ret = snd_ctl_elem_write(handle, control);
+	if (ret < 0) {
+		scn_error("%s: control %s failed: %s\n", __func__,
+			 setting->name, snd_strerror(ret));
+		scn_error("%s: count %d type: %d\n", __func__,
+			count, type);
+		for (i = 0; i < count; i++)
+			fprintf(stderr, "%d ", get_value(scn, setting, i));
+		return ret;
+	}
+	return 0;
+}
+
+static void exec_sequence(struct sequence_element *seq, struct snd_scenario
+			*scn, snd_ctl_elem_list_t *list, snd_ctl_t *handle)
+{
+	int count = snd_ctl_elem_list_get_count(list);
+	while (seq) {
+		if (seq->sleep)
+			usleep(seq->sleep);
+		else {
+			snd_ctl_elem_id_t *id;
+			snd_ctl_elem_id_alloca(&id);
+			int ret, i, numid;
+			/* Where is id lookup from numid if you need it? */
+			for (i = 0; i < count; ++i) {
+				snd_ctl_elem_list_get_id(list, i, id);
+				numid = snd_ctl_elem_id_get_numid(id);
+				if (numid == seq->control->id) {
+					ret = set_control(handle, id, scn);
+					if (ret < 0) {
+						scn_error("%s: failed to set control %s\n",
+							__func__, scn->card_name);
+					}
+					break;
+				}
+			}
+		}
+		seq = seq->next;
+	}
+}
+
+int snd_scenario_set_scn(struct snd_scenario *scn, const char *name)
+{
+	snd_ctl_card_info_t *info;
+	snd_ctl_elem_list_t *list;
+	snd_ctl_t *handle;
+	int ret, count, i;
+
+	snd_ctl_card_info_alloca(&info);
+	snd_ctl_elem_list_alloca(&list);
+
+	/* find scenario name */
+	for (i = 0; i < scn->num_scenarios; i++) {
+		if (!strcmp(scn->scenario[i].name, name))
+			goto found;
+	}
+	scn_error("%s: scenario %s not found\n", __func__, name);
+	return -EINVAL;
+
+found:
+	/* scenario found - now open card */
+	scn->current_scenario = i;
+	ret = snd_ctl_open(&handle, scn->card_name, 0);
+	if (ret) {
+		scn_error("%s: control %s open error: %s\n", __func__,
+			scn->card_name, snd_strerror(ret));
+		return ret;
+	}
+
+	ret = snd_ctl_card_info(handle, info);
+	if (ret < 0) {
+		scn_error("%s :control %s local retor: %s\n", __func__,
+			scn->card_name, snd_strerror(ret));
+		goto close;
+	}
+
+	ret = snd_ctl_elem_list(handle, list);
+	if (ret < 0) {
+		scn_error("%s: cannot determine controls: %s\n", __func__,
+			snd_strerror(ret));
+		goto close;
+	}
+
+	count = snd_ctl_elem_list_get_count(list);
+	if (count < 0) {
+		ret = 0;
+		goto close;
+	}
+
+	snd_ctl_elem_list_set_offset(list, 0);
+	if (snd_ctl_elem_list_alloc_space(list, count) < 0) {
+		scn_error("%s: not enough memory...\n", __func__);
+		ret =  -ENOMEM;
+		goto close;
+	}
+	if ((ret = snd_ctl_elem_list(handle, list)) < 0) {
+		scn_error("%s: cannot determine controls: %s\n", __func__,
+			snd_strerror(ret));
+		goto free;
+	}
+
+	/* If we have a sequence list that should be executed before the new
+	 * scenario is set do it now */
+	if (scn->pre_seq_list)
+		exec_sequence(scn->pre_seq_list, scn, list, handle);
+
+	/* iterate through each kcontrol and add to db */
+	for (i = 0; i < count; ++i) {
+		snd_ctl_elem_id_t *id;
+		snd_ctl_elem_id_alloca(&id);
+		snd_ctl_elem_list_get_id(list, i, id);
+
+		ret = set_control(handle, id, scn);
+		if (ret < 0) {
+			scn_error("%s: failed to set control %s\n", __func__,
+				scn->card_name);
+		}
+	}
+
+	/* If we have a sequence list that should be executed after the new
+	 * scenario is set do it now */
+	if (scn->post_seq_list)
+		exec_sequence(scn->post_seq_list, scn, list, handle);
+
+free:
+	snd_ctl_elem_list_free_space(list);
+close:
+	snd_ctl_close(handle);
+	return ret;
+}
+
+int snd_scenario_dump(const char *card_name)
+{
+	snd_ctl_t *handle;
+	snd_ctl_card_info_t *info;
+	snd_ctl_elem_list_t *list;
+	int ret, i, count;
+
+	snd_ctl_card_info_alloca(&info);
+	snd_ctl_elem_list_alloca(&list);
+
+	/* open and load snd card */
+	ret = snd_ctl_open(&handle, card_name, SND_CTL_READONLY);
+	if (ret < 0) {
+		scn_error("%s: control %s open retor: %s\n", __func__, card_name,
+			snd_strerror(ret));
+		return ret;
+	}
+
+	ret = snd_ctl_card_info(handle, info);
+	if (ret < 0) {
+		scn_error("%s :control %s local retor: %s\n", __func__,
+			card_name, snd_strerror(ret));
+		goto close;
+	}
+
+	ret = snd_ctl_elem_list(handle, list);
+	if (ret < 0) {
+		scn_error("%s: cannot determine controls: %s\n", __func__,
+			snd_strerror(ret));
+		goto close;
+	}
+
+	count = snd_ctl_elem_list_get_count(list);
+	if (count < 0) {
+		ret = 0;
+		goto close;
+	}
+
+	snd_ctl_elem_list_set_offset(list, 0);
+	if (snd_ctl_elem_list_alloc_space(list, count) < 0) {
+		scn_error("%s: not enough memory...\n", __func__);
+		ret =  -ENOMEM;
+		goto close;
+	}
+	if ((ret = snd_ctl_elem_list(handle, list)) < 0) {
+		scn_error("%s: cannot determine controls: %s\n", __func__,
+			snd_strerror(ret));
+		goto free;
+	}
+
+	/* iterate through each kcontrol and add to db */
+	for (i = 0; i < count; ++i) {
+		snd_ctl_elem_id_t *id;
+		snd_ctl_elem_id_alloca(&id);
+		snd_ctl_elem_list_get_id(list, i, id);
+
+		ret = dump_control(handle, id);
+		if (ret < 0) {
+			scn_error("%s: cannot determine controls: %s\n",
+				__func__, snd_strerror(ret));
+			goto free;
+		}
+	}
+free:
+	snd_ctl_elem_list_free_space(list);
+close:
+	snd_ctl_close(handle);
+	return ret;
+}
+
+const char *snd_scenario_get_scn(struct snd_scenario *scn)
+{
+	if (scn->current_scenario > 0 && scn->current_scenario < MAX_SCN)
+		return scn->scenario[scn->current_scenario].name;
+	else
+		return NULL;
+}
+
+int snd_scenario_set_qos(struct snd_scenario *scn, int qos)
+{
+	/* TODO: change QoS kcontrols */
+	scn->scenario[scn->current_scenario].qos = qos;
+	return 0;
+}
+
+int snd_scenario_get_qos(struct snd_scenario *scn)
+{
+	return scn->scenario[scn->current_scenario].qos;
+}
+
+int snd_scenario_get_master_playback_volume(struct snd_scenario *scn)
+{
+	return scn->scenario[scn->current_scenario].playback_volume_id;
+}
+
+int snd_scenario_get_master_playback_switch(struct snd_scenario *scn)
+{
+	return scn->scenario[scn->current_scenario].playback_switch_id;
+}
+
+int snd_scenario_get_master_capture_volume(struct snd_scenario *scn)
+{
+	return scn->scenario[scn->current_scenario].capture_volume_id;
+}
+
+int snd_scenario_get_master_capture_switch(struct snd_scenario *scn)
+{
+	return scn->scenario[scn->current_scenario].capture_switch_id;
+}
+
+int snd_scenario_list(struct snd_scenario *scn, const char **list[])
+{
+	*list = scn->list;
+	return scn->num_scenarios;
+}
-- 
1.6.4.3

regards
Stefan Schmidt

  parent reply	other threads:[~2009-10-01 15:09 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-10-01  9:47 [RFC] Add scenario management Stefan Schmidt
2009-10-01  9:47 ` [PATCH] ascenario: Add scenario support to alsa-lib Stefan Schmidt
2009-10-01 12:28   ` Mark Brown
2009-10-01 12:48     ` Liam Girdwood
2009-10-01 13:02       ` Mark Brown
2009-10-01 14:06         ` Liam Girdwood
2009-10-01 14:18           ` Mark Brown
2009-10-01 13:19     ` Stefan Schmidt
2009-10-01 13:24       ` Mark Brown
2009-10-01 13:38         ` Stefan Schmidt
2009-10-01 13:39         ` pl bossart
2009-10-01 13:54           ` Liam Girdwood
2009-10-01 14:11           ` Stefan Schmidt
2009-10-01 15:08       ` Stefan Schmidt [this message]
2009-10-05  8:27         ` Stefan Schmidt
2009-10-05  9:14           ` Jaroslav Kysela
2009-10-05  9:35             ` Stefan Schmidt
2009-10-06  8:23               ` Jaroslav Kysela
2009-10-06  8:41                 ` Takashi Iwai
2009-10-06  9:00                   ` Jaroslav Kysela
2009-10-06  9:13                     ` Takashi Iwai
2009-10-07  8:10                       ` Jaroslav Kysela
2009-10-07  8:52                         ` Takashi Iwai
2009-10-07  9:47                           ` Jaroslav Kysela
2009-10-07  9:55                             ` Takashi Iwai
2009-10-06  9:28                     ` Takashi Iwai
2009-10-06 11:05                       ` Jaroslav Kysela
2009-10-06 13:33                         ` Jaroslav Kysela
2009-10-06 13:46                           ` Takashi Iwai
2009-10-07 13:48                             ` Stefan Schmidt
2009-10-06 15:12                           ` Stefan Schmidt
2009-10-06 15:54                             ` [PATCH 0/3] ascenario: Bring it to compile after API changes Stefan Schmidt
2009-10-06 15:54                             ` [PATCH 1/3] ascenario: Fix typedef for snd_scenario_t Stefan Schmidt
2009-10-06 16:04                               ` Takashi Iwai
2009-10-06 17:08                                 ` Stefan Schmidt
2009-10-06 17:16                                   ` Jaroslav Kysela
2009-10-06 17:42                                     ` Stefan Schmidt
2009-10-06 15:54                             ` [PATCH 2/3] ascenario: Fix usage of new typedefed snd_scenario_t Stefan Schmidt
2009-10-06 15:54                             ` [PATCH 3/3] ascenario: Catchup with function declaration changes Stefan Schmidt
2009-10-07 13:53                           ` [PATCH] ascenario: Add scenario support to alsa-lib Mark Brown
2009-10-06 10:29                 ` Stefan Schmidt
2009-10-01  9:47 ` [PATCH] ascenario: Add dump and configure utils for ascneario Stefan Schmidt
2009-10-02  9:12 ` [RFC] Add scenario management Takashi Iwai
2009-10-02  9:55   ` Stefan Schmidt
2009-10-02  9:58     ` Takashi Iwai
2009-10-02  9:58   ` Jaroslav Kysela
2009-10-02 10:12     ` Takashi Iwai
2009-10-02 10:45     ` Liam Girdwood
2009-10-02 11:03       ` Jaroslav Kysela

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20091001150849.GE5936@excalibur.local \
    --to=stefan@datenfreihafen.org \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@opensource.wolfsonmicro.com \
    --cc=gg@slimlogic.co.uk \
    --cc=ian@mnementh.co.uk \
    --cc=lrg@slimlogic.co.uk \
    --cc=stefan@slimlogic.co.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.