Re: [PATCH] ascenario: Add scenario support to alsa-lib

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello.

On Thu, 2009-10-01 at 17:08, Stefan Schmidt wrote:
> 
> For an updated patch with all your comments inlcuded see below.

Here is another update on this patch. Fixed a problem I introduced in the last
iteration and changed the config tokens from MasterPlaybackVolume to Master
Playback Volume, etc. That's based on a siggestion from Mark which we had
offlist. Let me quote it here to explain the good reasoning behind it.

--- snip ---
If we reuse the standard ALSA control names as the tokens then someone
could come along in the future and extend the library to allow any
control to be included in the scenarios and existing scenario setups
would just work transparently without having the configuration have
multiple ways of specifying the same thing.  An extension like that
would move any questions about what can be included in the scenario out
of the library which should make it easier to maintian and less likely
to restrict the odd things that some users will inevitably wish to do
with it.
--- snap ---


>From cbde1540f8b2bc797ca9668f3134ae35c5f79361 Mon Sep 17 00:00:00 2001
From: Stefan Schmidt <stefan@xxxxxxxxxxxxxxx>
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@xxxxxxxxxxxxxx>
CC: Graeme Gregory <gg@xxxxxxxxxxxxxxx>
Signed-off-by: Liam Girdwood <lrg@xxxxxxxxxxxxxxx>
Signed-off-by: Stefan Schmidt <stefan@xxxxxxxxxxxxxxx>
---
 include/Makefile.am |    2 +-
 include/ascenario.h |  170 +++++++
 src/Makefile.am     |    2 +-
 src/ascenario.c     | 1360 +++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1532 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@xxxxxxxxxxxxxxx>
+*           Stefan Schmidt <stefan@xxxxxxxxxxxxxxx>
+*/
+
+/**
+ * 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..99f239e
--- /dev/null
+++ b/src/ascenario.c
@@ -0,0 +1,1360 @@
+/*
+ *  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@xxxxxxxxxxxxxxx>
+ *	     Stefan Schmidt <stefan@xxxxxxxxxxxxxxx>
+ */
+
+#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, len, offset;
+	char buf[MAX_BUF], *tbuf;
+
+	offset = sizeof(scn->scenario);
+	scn->scenario = realloc(scn->scenario,
+		(scn->num_scenarios + 1) * sizeof(struct scenario_info));
+	len = sizeof(scn->scenario) - offset;
+	if (scn->scenario == NULL)
+		return -ENOMEM;
+	bzero(scn->scenario + offset, len);
+	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, "Master Playback Volume", 22) == 0) {
+			info->playback_volume_id = get_int(tbuf + 22);
+			if (info->playback_volume_id < 0) {
+				scn_error("%s: failed to get Master Playback Volume\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "Master Playback Switch", 22) == 0) {
+			info->playback_switch_id = get_int(tbuf + 22);
+			if (info->playback_switch_id < 0) {
+				scn_error("%s: failed to get Master Playback Switch\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "Master Capture Volume", 21) == 0) {
+			info->capture_volume_id = get_int(tbuf + 21);
+			if (info->capture_volume_id < 0) {
+				scn_error("%s: failed to get Master Capture Volume\n",
+					__func__);
+				goto err;
+			}
+			continue;
+		}
+
+		if (strncmp(tbuf, "Master Capture Switch", 21) == 0) {
+			info->capture_switch_id = get_int(tbuf + 21);
+			if (info->capture_switch_id < 0) {
+				scn_error("%s: failed to get Master Capture Switch\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
_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux